Java中如何获取第一个非空值?

发布于 2024-08-31 10:56:00 字数 427 浏览 3 评论 0 原文

Java 中是否存在与 SQL 的 COALESCE 函数等效的函数?也就是说,有没有办法返回几个变量的第一个非空值?

例如,

Double a = null;
Double b = 4.4;
Double c = null;

我想以某种方式有一个语句返回 abc 的第一个非空值 - 在这种情况下,它将返回b,或4.4。 (类似于 sql 方法 - 返回 COALESCE(a,b,c))。我知道我可以通过以下方式明确地做到这一点:

return a != null ? a : (b != null ? b : c)

但我想知道是否有任何内置的、可接受的函数来完成此操作。

Is there a Java equivalent of SQL's COALESCE function? That is, is there any way to return the first non-null value of several variables?

e.g.

Double a = null;
Double b = 4.4;
Double c = null;

I want to somehow have a statement that will return the first non-null value of a, b, and c - in this case, it would return b, or 4.4. (Something like the sql method - return COALESCE(a,b,c)). I know that I can do it explicitly with something like:

return a != null ? a : (b != null ? b : c)

But I wondered if there was any built-in, accepted function to accomplish this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

十秒萌定你 2024-09-07 10:56:00

不,没有。

您可以获得的最接近结果是:

public static <T> T coalesce(T ...items) {
    for (T i : items) if (i != null) return i;
    return null;
}

出于高效原因,您可以按如下方式处理常见情况:

public static <T> T coalesce(T a, T b) {
    return a == null ? b : a;
}
public static <T> T coalesce(T a, T b, T c) {
    return a != null ? a : (b != null ? b : c);
}
public static <T> T coalesce(T a, T b, T c, T d) {
    return ...
}

高效原因是每次调用该方法的 ... 版本时都会发生数组分配。这对于一大堆物品来说可能会造成浪费,我怀疑这将是常见的用法。

No, there isn't.

The closest you can get is:

public static <T> T coalesce(T ...items) {
    for (T i : items) if (i != null) return i;
    return null;
}

For efficient reasons, you can handle the common cases as follows:

public static <T> T coalesce(T a, T b) {
    return a == null ? b : a;
}
public static <T> T coalesce(T a, T b, T c) {
    return a != null ? a : (b != null ? b : c);
}
public static <T> T coalesce(T a, T b, T c, T d) {
    return ...
}

The efficiency reason is that an array allocation will happen each time you invoke the ... version of the method. This could be wasteful for hand-fulls of items, which I suspect will be common usage.

剩余の解释 2024-09-07 10:56:00

如果只有两个要测试的引用并且您使用的是 Java 8,则可以使用

Object o = null;
Object p = "p";
Object r = Optional.ofNullable( o ).orElse( p );
System.out.println( r );   // p

如果导入 static 可选,则表达式还不错。

不幸的是,您的“几个变量”的情况不可能使用可选方法。相反,你可以使用:

Object o = null;
Object p = null;
Object q = "p";

Optional<Object> r = Stream.of( o, p, q ).filter( Objects::nonNull ).findFirst();
System.out.println( r.orElse(null) );   // p

If there are only two references to test and you are using Java 8, you could use

Object o = null;
Object p = "p";
Object r = Optional.ofNullable( o ).orElse( p );
System.out.println( r );   // p

If you import static Optional the expression is not too bad.

Unfortunately your case with "several variables" is not possible with an Optional-method. Instead you could use:

Object o = null;
Object p = null;
Object q = "p";

Optional<Object> r = Stream.of( o, p, q ).filter( Objects::nonNull ).findFirst();
System.out.println( r.orElse(null) );   // p
℉絮湮 2024-09-07 10:56:00

如果只需要检查两个变量并且您使用的是 Guava,则可以使用 MoreObjects.firstNonNull(T 第一,T 第二)

If there are only two variables to check and you're using Guava, you can use MoreObjects.firstNonNull(T first, T second).

定格我的天空 2024-09-07 10:56:00

根据 LES2 的答案,您可以通过调用重载函数来消除高效版本中的一些重复:

public static <T> T coalesce(T a, T b) {
    return a != null ? a : b;
}
public static <T> T coalesce(T a, T b, T c) {
    return a != null ? a : coalesce(b,c);
}
public static <T> T coalesce(T a, T b, T c, T d) {
    return a != null ? a : coalesce(b,c,d);
}
public static <T> T coalesce(T a, T b, T c, T d, T e) {
    return a != null ? a : coalesce(b,c,d,e);
}

Following on from LES2's answer, you can eliminate some repetition in the efficient version, by calling the overloaded function:

public static <T> T coalesce(T a, T b) {
    return a != null ? a : b;
}
public static <T> T coalesce(T a, T b, T c) {
    return a != null ? a : coalesce(b,c);
}
public static <T> T coalesce(T a, T b, T c, T d) {
    return a != null ? a : coalesce(b,c,d);
}
public static <T> T coalesce(T a, T b, T c, T d, T e) {
    return a != null ? a : coalesce(b,c,d,e);
}
北笙凉宸 2024-09-07 10:56:00

这种情况需要一些预处理器。因为如果您编写一个选择第一个非空值的函数(静态方法),它将评估所有项目。如果某些项目是方法调用(可能是耗时的方法调用),则会出现问题。即使这些方法之前的任何项不为空,也会调用该方法。

应该使用像这样的一些函数

public static <T> T coalesce(T ...items) …

,但在编译成字节代码之前,应该有一个预处理器来找到这个“合并函数”的用法,并将其替换为像

a != null ? a : (b != null ? b : c)

更新2014-09-02:

感谢Java 8 和 Lambda 有可能在 Java 中实现真正的合并!包括关键的功能:仅在需要时才评估特定表达式 - 如果前面的表达式不为空,则不会评估后面的表达式(不调用方法,不执行计算或磁盘/网络操作)。

我写了一篇关于它的文章 Java 8:合并 – hledáme neNULLové hodnoty – (用捷克语编写,但我希望每个人都能理解代码示例)。

This situation calls for some preprocessor. Because if you write a function (static method) which picks the first not null value, it evaluates all items. It is problem if some items are method calls (may be time expensive method calls). And this methods are called even if any item before them is not null.

Some function like this

public static <T> T coalesce(T ...items) …

should be used but before compiling into byte code there should be a preprocessor which find usages of this „coalesce function“ and replaces it with construction like

a != null ? a : (b != null ? b : c)

Update 2014-09-02:

Thanks to Java 8 and Lambdas there is possibility to have true coalesce in Java! Including the crucial feature: particular expressions are evaluated only when needed – if earlier one is not null, then following ones are not evaluated (methods are not called, computation or disk/network operations are not done).

I wrote an article about it Java 8: coalesce – hledáme neNULLové hodnoty – (written in Czech, but I hope that code examples are understandable for everyone).

流绪微梦 2024-09-07 10:56:00

从 Java 9 开始,有内置的 Objects.requireNonNullElse 方法用于两个参数合并。这对我来说是最有用的。

Since Java 9 there is builtin Objects.requireNonNullElse method for two parameter coalesce. That was the most useful for me.

梦在深巷 2024-09-07 10:56:00

您可以尝试以下操作:

public static <T> T coalesce(T... t) {
    return Stream.of(t).filter(Objects::nonNull).findFirst().orElse(null);
}

基于响应

You can try this:

public static <T> T coalesce(T... t) {
    return Stream.of(t).filter(Objects::nonNull).findFirst().orElse(null);
}

Based on this response

空城缀染半城烟沙 2024-09-07 10:56:00

使用 Guava,您可以执行以下操作:

Optional.fromNullable(a).or(b);

如果 ab 都为 null,则不会抛出 NPE。

编辑:我错了,它确实抛出了 NPE。 Michal Čizmazia 评论的正确方法是:

Optional.fromNullable(a).or(Optional.fromNullable(b)).orNull();

With Guava you can do:

Optional.fromNullable(a).or(b);

which doesn't throw NPE if both a and b are null.

EDIT: I was wrong, it does throw NPE. The correct way as commented by Michal Čizmazia is:

Optional.fromNullable(a).or(Optional.fromNullable(b)).orNull();
若沐 2024-09-07 10:56:00

当您想避免评估某些昂贵的方法时,使用供应商怎么样?

像这样:

public static <T> T coalesce(Supplier<T>... items) {
for (Supplier<T> item : items) {
    T value = item.get();
    if (value != null) {
        return value;
    }
    return null;
}

然后像这样使用它:

Double amount = coalesce(order::firstAmount, order::secondAmount, order::thirdAmount)

您还可以使用重载方法来进行带有两个、三个或四个参数的调用。

此外,您还可以使用流,如下所示:

public static <T> T coalesce2(Supplier<T>... s) {
    return Arrays.stream(s).map(Supplier::get).filter(Objects::nonNull).findFirst().orElse(null);
}

How about using suppliers when you want to avoid evaluating some expensive method?

Like this:

public static <T> T coalesce(Supplier<T>... items) {
for (Supplier<T> item : items) {
    T value = item.get();
    if (value != null) {
        return value;
    }
    return null;
}

And then using it like this:

Double amount = coalesce(order::firstAmount, order::secondAmount, order::thirdAmount)

You can also use overloaded methods for the calls with two, three or four arguments.

In addition, you could also use streams with something like this:

public static <T> T coalesce2(Supplier<T>... s) {
    return Arrays.stream(s).map(Supplier::get).filter(Objects::nonNull).findFirst().orElse(null);
}
心病无药医 2024-09-07 10:56:00

为了完整性,“多个变量”的情况确实是可能的,尽管一点也不优雅。例如,对于变量 opq

Optional.ofNullable( o ).orElseGet(()-> Optional.ofNullable( p ).orElseGet(()-> q ) )

请注意使用 orElseGet() 来处理opq 不是变量,而是表达式,要么成本高昂,要么具有不良副作用。

在最一般的情况下,coalesce(e[1],e[2],e[3],...,e[N])

coalesce-expression(i) ==  e[i]  when i = N
coalesce-expression(i) ==  Optional.ofNullable( e[i] ).orElseGet(()-> coalesce-expression(i+1) )  when i < N

这可能会生成过长的表达式。然而,如果我们试图进入一个没有 null 的世界,那么 v[i] 很可能已经是 Optional 类型了,而不是简单的String。在这种情况下,

result= o.orElse(p.orElse(q.get())) ;

或者在表达式的情况下:

result= o.orElseGet(()-> p.orElseGet(()-> q.get() ) ) ;

此外,如果您还转向函数声明式样式,则 opq 应该是 Supplier 类型,如下所示:

Supplier<String> q= ()-> q-expr ;
Supplier<String> p= ()-> Optional.ofNullable(p-expr).orElseGet( q ) ;
Supplier<String> o= ()-> Optional.ofNullable(o-expr).orElseGet( p ) ;

然后整个 coalesce 简单地简化为 o.get()

更具体的示例:

Supplier<Integer> hardcodedDefaultAge= ()-> 99 ;
Supplier<Integer> defaultAge= ()-> defaultAgeFromDatabase().orElseGet( hardcodedDefaultAge ) ;
Supplier<Integer> ageInStore= ()-> ageFromDatabase(memberId).orElseGet( defaultAge ) ;
Supplier<Integer> effectiveAge= ()-> ageFromInput().orElseGet( ageInStore ) ;

defaultAgeFromDatabase()ageFromDatabase()ageFromInput() 已经返回 Optional< /代码>,自然。

然后,如果我们对 Supplier 感到满意,则 coalesce 变为 effectiveAge.get() 或简单地 effectiveAge >。

恕我直言,在 Java 8 中,我们将看到越来越多的这样结构的代码,因为它同时非常不言自明且高效,尤其是在更复杂的情况下。

我确实怀念一个类 Lazy,它只调用一次 Supplier,但很懒惰,以及 Optional< 定义的一致性。 T>(即Optional-Optional 运算符,甚至Supplier> )。

Just for completness, the "several variables" case is indeed possible, though not elegant at all. For example, for variables o, p, and q:

Optional.ofNullable( o ).orElseGet(()-> Optional.ofNullable( p ).orElseGet(()-> q ) )

Please note the use of orElseGet() attending to the case that o, p, and q are not variables but expressions either expensive or with undesired side-effects.

In the most general case coalesce(e[1],e[2],e[3],...,e[N])

coalesce-expression(i) ==  e[i]  when i = N
coalesce-expression(i) ==  Optional.ofNullable( e[i] ).orElseGet(()-> coalesce-expression(i+1) )  when i < N

This can generate expressions excessively long. However, if we are trying to move to a world without null, then v[i] are most probably already of type Optional<String>, as opposed to simply String. In this case,

result= o.orElse(p.orElse(q.get())) ;

or in the case of expressions:

result= o.orElseGet(()-> p.orElseGet(()-> q.get() ) ) ;

Furthermore, if you are also moving to a functional-declarative style, o, p, and q should be of type Supplier<String> like in:

Supplier<String> q= ()-> q-expr ;
Supplier<String> p= ()-> Optional.ofNullable(p-expr).orElseGet( q ) ;
Supplier<String> o= ()-> Optional.ofNullable(o-expr).orElseGet( p ) ;

And then the whole coalesce reduces simply to o.get().

For a more concrete example:

Supplier<Integer> hardcodedDefaultAge= ()-> 99 ;
Supplier<Integer> defaultAge= ()-> defaultAgeFromDatabase().orElseGet( hardcodedDefaultAge ) ;
Supplier<Integer> ageInStore= ()-> ageFromDatabase(memberId).orElseGet( defaultAge ) ;
Supplier<Integer> effectiveAge= ()-> ageFromInput().orElseGet( ageInStore ) ;

defaultAgeFromDatabase(), ageFromDatabase(), and ageFromInput() would already return Optional<Integer>, naturally.

And then the coalesce becomes effectiveAge.get() or simply effectiveAge if we are happy with a Supplier<Integer>.

IMHO, with Java 8 we will see more and more code structured like this, as it's extremely self-explainatory and efficient at the same time, especially in more complex cases.

I do miss a class Lazy<T> that invokes a Supplier<T> only one time, but lazily, as well as consistency in the definition of Optional<T> (i.e. Optional<T>-Optional<T> operators, or even Supplier<Optional<T>>).

请爱~陌生人 2024-09-07 10:56:00

(与其他答案类似,但我想更详尽地描述 Guava 的 MoreObjects.firstNonNull()、Apache Commons Lang 3 ObjectUtils.firstNonNull() Java 9 中引入了 >java.util.Objects.requireNonNullElse()requireNonNullElseGet() 方法。)

这个答案很长 - 如果您想了解,请参阅最后的 TL;DR只需跳至摘要即可。

Guava MoreObjects.firstNonNull(T, T)

Guava 的 MoreObjects.firstNonNull(T, T) 是这样描述的。重要的部分是如果 {@code first} 和 {@code secondary} 都为 null,则@throws NullPointerException。此方法要求其中一个对象为非空

公共静态; TfirstNonNull(@CheckForNull T 第一,@CheckForNull T 第二)

返回两个给定参数中不为 null 的第一个(如果其中一个为 null),否则抛出 NullPointerException

要查找可迭代对象中的第一个非空元素,请使用Iterables.find(iterable, Predicates.notNull())。对于可变参数,请使用 Iterables.find(Arrays.asList(a, b, c, ...), Predicates.notNull()),必要时进行静态导入。

注意:如果first表示为可选,则可以使用first.or(second)来完成。该方法还允许使用first.or(supplier) 对后备实例进行惰性评估。

Java 9 用户:改用 java.util.Objects.requireNonNullElse(first, secondary)`。

退货:
first 如果它是非null;否则,如果它是非null

,则为第二个

抛出
java.lang.NullPointerException - 如果 firstsecond 均为 null

自:
18.0(自 3.0 起为 Objects.firstNonNull())

Apache Commons Lang 3 ObjectUtils.firstNonNull()defaultIfNull(T, T)

ObjectUtils.firstNonNull(T...) 另一方面,对空值的处理更加“宽松”。如果所有值都为 null,那么该方法将简单地返回 null。对于某些情况,这可能更好(只要调用代码正确处理 null 返回值)。

另请注意,这需要一个 T... 可变参数,因此它可以与两个以上的参数一起使用,这与其他选项不同。

公共静态; TfirstNonNull(T...值)

返回数组中第一个不为null的值。如果所有值均为 null 或数组为 null 或空,则返回 null

ObjectUtils.firstNonNull(null, null) = null
ObjectUtils.firstNonNull(null, "") = ""
ObjectUtils.firstNonNull(null, null, "") = ""
ObjectUtils.firstNonNull(null, "zz") = "zz"
ObjectUtils.firstNonNull("abc", *) = "abc"
ObjectUtils.firstNonNull(null, "xyz", *) = "xyz"
ObjectUtils.firstNonNull(Boolean.TRUE, *) = Boolean.TRUE
ObjectUtils.firstNonNull() = null

类型参数:
T - 数组的组件类型

参数:
values - 要测试的值,可以为 null 或空

退货:
值中非 null 的第一个值,如果没有非 null 值,则为 null

自:
3.0

ObjectUtils.defaultIfNull(T, T) 方法也存在,并且具有类似的 null 语义,但针对两者进行了稍微优化-参数场景。

JDK java.util.Objects.requireNonNullElserequireNonNullElseGet 方法

Objects.requireNonNullElse(T, T) 具有以下语义。它与 Guava MoreObjects.firstNonNull() 方法非常接近,它应该是该方法的直接替代品。

公共静态; T requireNonNullElse (T obj, T defaultObj)

如果第一个参数非 null,则返回它,否则返回非 null 第二个参数。

类型参数:
T - 引用的类型

参数:
obj - 一个对象
defaultObj - 如果第一个参数为 null

,则返回一个非 null 对象

退货:
如果第一个参数为非 null,则为第二个参数;如果为非 null

,则为第二个参数

抛出:
NullPointerException - 如果 obj 均为 nulldefaultObjnull

自:
9

最后,Objects.requireNonNullElseGet(T obj,Suppliersupplier) 方法。如果创建回退值是一项较繁重的操作,而您希望在 obj 为非 null 时避免这种操作,那么它会很有用。

公共静态; T requireNonNullElseGet(T obj,Suppliersupplier)

如果第一个参数非 null,则返回该参数,否则返回 supplier.get() 的非 null 值。< /p>

类型参数:
T - 第一个参数的类型和返回类型

参数:
obj - 一个对象
supplier - 如果第一个参数为 null

,则返回非 null 对象

退货:
如果为非 null,则为第一个参数;如果为非 null

,则为 supplier.get() 的值

抛出:
NullPointerException - 如果 obj 均为 null 并且 suppliernullsupplier.get() 值为 null

自:
9

TL;DR

(Similar to other answers, but I wanted to more exhaustively describe the differences between Guava's MoreObjects.firstNonNull(), Apache Commons Lang 3 ObjectUtils.firstNonNull() and the java.util.Objects.requireNonNullElse() and requireNonNullElseGet() methods introduced in Java 9.)

This answer is long - see the TL;DR at the end if you are want to just skip to the summary.

Guava MoreObjects.firstNonNull(T, T)

Guava's MoreObjects.firstNonNull(T, T) is described like this. The important part is the @throws NullPointerException if both {@code first} and {@code second} are null. This method requires that either one of the objects are non-null

public static <T> T firstNonNull​(@CheckForNull T first, @CheckForNull T second)

Returns the first of two given parameters that is not null, if either is, or otherwise throws a NullPointerException.

To find the first non-null element in an iterable, use Iterables.find(iterable, Predicates.notNull()). For varargs, use Iterables.find(Arrays.asList(a, b, c, ...), Predicates.notNull()), static importing as necessary.

Note: if first is represented as an Optional, this can be accomplished with first.or(second). That approach also allows for lazy evaluation of the fallback instance, using first.or(supplier).

Java 9 users: use java.util.Objects.requireNonNullElse(first, second)` instead.

Returns:
first if it is non-null; otherwise second if it is non-null

Throws:
java.lang.NullPointerException - if both first and second are null

Since:
18.0 (since 3.0 as Objects.firstNonNull()).

Apache Commons Lang 3 ObjectUtils.firstNonNull() and defaultIfNull(T, T)

ObjectUtils.firstNonNull(T...) on the other hand, has a much more "relaxed" handling of null values. If all values are null, well, then the method simply returns null. For some cases, this might be preferable (as long as the calling code handles null return values properly).

Also note that this takes a T... variable argument parameter, so it can be used with more than two parameters, unlike the other options.

public static <T> T firstNonNull(T... values)

Returns the first value in the array which is not null. If all the values are null or the array is null or empty then null is returned.

ObjectUtils.firstNonNull(null, null) = null
ObjectUtils.firstNonNull(null, "") = ""
ObjectUtils.firstNonNull(null, null, "") = ""
ObjectUtils.firstNonNull(null, "zz") = "zz"
ObjectUtils.firstNonNull("abc", *) = "abc"
ObjectUtils.firstNonNull(null, "xyz", *) = "xyz"
ObjectUtils.firstNonNull(Boolean.TRUE, *) = Boolean.TRUE
ObjectUtils.firstNonNull() = null

Type Parameters:
T - the component type of the array

Parameters:
values - the values to test, may be null or empty

Returns:
the first value from values which is not null, or null if there are no non-null values

Since:
3.0

The ObjectUtils.defaultIfNull(T, T) method also exists, and has similar null semantics, but is slightly more optimized for the two-parameter scenario.

JDK java.util.Objects.requireNonNullElse and requireNonNullElseGet methods

Objects.requireNonNullElse(T, T) has the following semantics. It matches the Guava MoreObjects.firstNonNull() method quite closely, it should be pretty much a drop-in replacement for that method.

public static <T> T requireNonNullElse​(T obj, T defaultObj)

Returns the first argument if it is non-null and otherwise returns the non-null second argument.

Type Parameters:
T - the type of the reference

Parameters:
obj - an object
defaultObj - a non-null object to return if the first argument is null

Returns:
the first argument if it is non-null and otherwise the second argument if it is non-null

Throws:
NullPointerException - if both obj is null and defaultObj is null

Since:
9

Finally, the Objects.requireNonNullElseGet(T obj, Supplier<? extends T> supplier) method. It can be useful if creating the fallback value is a more heavy operation that you want to avoid if obj is non-null.

public static <T> T requireNonNullElseGet​(T obj, Supplier<? extends T> supplier)

Returns the first argument if it is non-null and otherwise returns the non-null value of supplier.get().

Type Parameters:
T - the type of the first argument and return type

Parameters:
obj - an object
supplier - of a non-null object to return if the first argument is null

Returns:
the first argument if it is non-null and otherwise the value from supplier.get() if it is non-null

Throws:
NullPointerException - if both obj is null and either the supplier is null or the supplier.get() value is null

Since:
9

TL;DR

生生漫 2024-09-07 10:56:00

怎么样:

firstNonNull = FluentIterable.from(
    Lists.newArrayList( a, b, c, ... ) )
        .firstMatch( Predicates.notNull() )
            .or( someKnownNonNullDefault );

Java ArrayList 方便地允许空条目,并且无论要考虑的对象数量如何,该表达式都是一致的。 (在这种形式中,考虑的所有对象都必须属于同一类型。)

How about:

firstNonNull = FluentIterable.from(
    Lists.newArrayList( a, b, c, ... ) )
        .firstMatch( Predicates.notNull() )
            .or( someKnownNonNullDefault );

Java ArrayList conveniently allows null entries and this expression is consistent regardless of the number of objects to be considered. (In this form, all the objects considered need to be of the same type.)

回忆躺在深渊里 2024-09-07 10:56:00
Object coalesce(Object... objects)
{
    for(Object o : object)
        if(o != null)
            return o;
    return null;
}
Object coalesce(Object... objects)
{
    for(Object o : object)
        if(o != null)
            return o;
    return null;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文