176

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

例如

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

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

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

但我想知道是否有任何内置的、被接受的功能来完成这个。

4

13 回答 13

260

阿帕奇共享语言 3

ObjectUtils.firstNonNull(T...)

Java 8 流

Stream.of(T...).filter(Objects::nonNull).findFirst().orElse(null)

于 2013-09-11T12:51:47.723 回答
124

不,没有。

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

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 ...
}
于 2010-05-04T18:47:31.573 回答
61

如果只有两个变量要检查并且您正在使用 Guava,则可以使用MoreObjects.firstNonNull(T first, T second)

于 2011-07-18T19:48:35.547 回答
57

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

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

如果您导入静态可选,则表达式还不错。

不幸的是,使用可选方法无法实现“多个变量”的情况。相反,您可以使用:

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
于 2015-02-03T18:36:39.843 回答
24

继 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);
}
于 2010-05-04T19:04:47.233 回答
11

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

像这样的一些功能

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

应该使用,但在编译成字节码之前应该有一个预处理器,它可以找到这个“coalesce function”的用法,并用类似的结构替换它

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

2014 年 9 月 2 日更新:

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

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

于 2012-02-19T18:45:24.863 回答
6

你可以试试这个:

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

基于响应

于 2018-01-10T17:28:40.577 回答
5

使用番石榴,您可以:

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

如果两者都是a,则不会抛出 NPE 。bnull

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

Optional.fromNullable(a).or(Optional.fromNullable(b)).orNull();
于 2013-07-25T07:31:01.097 回答
4

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

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

请注意,注意orElseGet(),op不是q变量而是表达式昂贵或具有不希望的副作用的情况。

在最一般的情况下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>,而不是简单String的 。在这种情况下,

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

或者在表达式的情况下:

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

此外,如果您也转向函数式声明风格,o, p, 并且q应该是如下类型Supplier<String>

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<Integer>自然地返回了。

然后如果我们对 a 感到满意,coalesce就变成effectiveAge.get()或简单地说。effectiveAgeSupplier<Integer>

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

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

于 2015-03-18T16:45:37.147 回答
4

当您想避免评估一些昂贵的方法时,如何使用供应商?

像这样:

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);
}
于 2018-04-20T08:21:26.453 回答
1

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

于 2021-12-17T07:35:58.073 回答
0

怎么样:

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

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

于 2016-12-16T04:28:55.143 回答
-2
Object coalesce(Object... objects)
{
    for(Object o : object)
        if(o != null)
            return o;
    return null;
}
于 2010-05-04T18:47:58.000 回答