如何获得Java中的第一个非空值?
有没有SQL的COALESCE
函数的Java等价物? 也就是说,有什么办法可以返回几个variables的第一个非空值?
例如
Double a = null; Double b = 4.4; Double c = null;
我想以某种方式有一个语句,将返回a
, b
和c
的第一个非空值 – 在这种情况下,它会返回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);
如果a
和b
都为null
,则不会抛出NPE。
编辑:我错了,它确实扔NPE。 MichalČizmazia评论的正确方法是:
Optional.fromNullable(a).or(Optional.fromNullable(b)).orNull();
为了完整性,“几个variables”的情况确实是可能的,尽pipe并不优雅。 例如,对于variableso
, p
和q
:
Optional.ofNullable( o ).orElseGet(()-> Optional.ofNullable( p ).orElseGet(()-> q ) )
请注意,使用orElseGet()
来处理o
, p
和q
不是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声明式样式, o
, p
和q
应该是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。)