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

有没有SQL的COALESCE函数的Java等价物? 也就是说,有什么办法可以返回几个variables的第一个非空值?

例如

 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) 

但是我想知道是否有内置的,可以接受的function来完成这个function。

不,没有。

你可以得到最接近的是:

 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 ... } 

ObjectUtils.firstNonNull(T...) ,来自Apache Commons Lang 3,听起来就像解决了这个问题。

如果你正在使用番石榴,你可以使用MoreObjects.firstNonNull(T …) 。

如果只有两个引用来testing,而您正在使用Java 8,则可以使用

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

如果你导入静态可选的expression式不是太糟糕。

不幸的是,对于“多个variables”,使用可选方法是不可能的。 相反,你可以使用:

 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 

继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); } 

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

有些function是这样的

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

应该被使用,但是在编译成字节码之前,应该有一个预处理器,它可以find这个“合并函数”的用法,并用结构replace它

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

更新2014-09-02:

感谢Java 8和Lambdas,可以在Java中实现真正的合并! 包括关键特性:特定的expression式只在需要的时候被评估 – 如果前面的一个不是null,那么下面的不被计算(方法不被调用,计算或者磁盘/networking操作没有被完成)。

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

用番石榴你可以做:

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

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

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

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

为了完整性,“几个variables”的情况确实是可能的,尽pipe并不优雅。 例如,对于variablesopq

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

请注意,使用orElseGet()来处理opq不是variables,而是expression式既昂贵又带有不希望的副作用。

在最一般情况下, 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 

这可能会产生过长的expression式。 然而,如果我们试图移动到一个没有null的世界,那么v[i]很可能已经是typesOptional<String> ,而不是简单的String 。 在这种情况下,

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

或者在expression式的情况下:

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

此外,如果您也正在转向function声明式样式, opq应该是typesSupplier<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>

然后,如果我们对Supplier<Integer>感到满意,那么coalesce变为effectiveAge.get()或简单effectiveAge

恕我直言,与Java 8,我们会看到越来越多的代码结构如此,因为它是非常自我解释和有效的在同一时间,尤其是在更复杂的情况下。

我错过了Lazy<T>类,它只调用了一次Supplier<T> ,但却很懒,还有Optional<T> (即Optional<T>Optional<T>运算符的定义的一致性,甚至Supplier<Optional<T>> )。

 Object coalesce(Object... objects) { for(Object o : object) if(o != null) return o; return null; } 

怎么样:

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

Java ArrayList方便地允许空条目,并且无论要考虑的对象的数量如何,该expression式都是一致的。 (在这种forms下,所有考虑的对象都必须是相同的types。)