是否存在SQL的COALESCE
函数的Java等价物?也就是说,有没有办法返回几个变量的第一个非空值?
e.g。
Double a = null;
Double b = 4.4;
Double c = null;
我想以某种方式有一个语句将返回a
,b
和c
的第一个非空值 - 在这种情况下,它将返回{{1} },或4.4。 (类似于sql方法 - 返回b
)。我知道我可以用以下内容明确地做到:
COALESCE(a,b,c)
但我想知道是否有任何内置的,可接受的功能来实现这一目标。
答案 0 :(得分:151)
Apache Commons Lang 3
ObjectUtils.firstNonNull(T...)
Java 8 Stream
Stream.of(T...).filter(Objects::nonNull).findFirst().orElse(null)
答案 1 :(得分:99)
不,没有。
最接近的是:
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 ...
}
答案 2 :(得分:53)
如果只检查两个变量,并且您正在使用Guava,则可以使用MoreObjects.firstNonNull(T first, T second)。
答案 3 :(得分:41)
如果只有两个测试引用并且您使用的是Java 8,则可以使用
Object o = null;
Object p = "p";
Object r = Optional.ofNullable( o ).orElse( p );
System.out.println( r ); // p
如果导入静态可选,表达式也不错。
不幸的是,使用Optional-method无法使用“几个变量”。相反,你可以使用:
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
答案 4 :(得分: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);
}
答案 5 :(得分:8)
这种情况需要一些预处理器。因为如果你编写一个函数(静态方法)来选择第一个非空值,它会评估所有项目。如果某些项是方法调用(可能是时间昂贵的方法调用),则会出现问题。即使前面的任何项不为空,也会调用此方法。
有些功能
public static <T> T coalesce(T ...items) …
应该使用但是在编译成字节代码之前应该有一个预处理器,它可以找到这个“coalesce function”的用法,并用
这样的结构替换它。a != null ? a : (b != null ? b : c)
更新2014-09-02:
感谢Java 8和Lambdas,有可能在Java中实现真正的合并!包括关键特性:特殊表达式仅在需要时进行评估 - 如果前一个不是null,则不评估后续的(不调用方法,不进行计算或磁盘/网络操作)。
我写了一篇关于它的文章Java 8: coalesce – hledáme neNULLové hodnoty - (用捷克语写的,但我希望代码示例对每个人都是可以理解的。)
答案 6 :(得分:5)
使用番石榴,你可以做到:
Optional.fromNullable(a).or(b);
如果a
和b
都是null
,则不会抛出NPE。
Optional.fromNullable(a).or(Optional.fromNullable(b)).orNull();
答案 7 :(得分:4)
仅仅为了完整性,“几个变量”的情况确实是可能的,尽管不是很优雅。例如,对于变量o
,p
和q
:
Optional.ofNullable( o ).orElseGet(()-> Optional.ofNullable( p ).orElseGet(()-> q ) )
请注意orElseGet()
使用o
,p
,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>
自然会返回coalesce
。
如果我们对effectiveAge.get()
感到满意,则effectiveAge
会变为Supplier<Integer>
或只是Lazy<T>
。
恕我直言,在Java 8中,我们将看到越来越多这样的代码,因为它同时具有极强的自我解释性和高效性,尤其是在更复杂的情况下。
我确实错过了Supplier<T>
课程Optional<T>
只调用Optional<T>
一次,但懒惰,以及Optional<T>
定义的一致性(即Supplier<Optional<T>>
- { {1}}运算符,甚至是{{1}})。
答案 8 :(得分:3)
你可以试试这个:
public static <T> T coalesce(T... t) {
return Stream.of(t).filter(Objects::nonNull).findFirst().orElse(null);
}
基于this回复
答案 9 :(得分:1)
当您想避免评估某些昂贵的方法时,如何使用供应商?
像这样:
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);
}
答案 10 :(得分:0)
怎么样:
firstNonNull = FluentIterable.from(
Lists.newArrayList( a, b, c, ... ) )
.firstMatch( Predicates.notNull() )
.or( someKnownNonNullDefault );
Java ArrayList可以方便地允许空条目,并且无论要考虑的对象数量如何,此表达式都是一致的。 (在这种形式下,所有考虑的对象必须属于同一类型。)
答案 11 :(得分:-1)
Object coalesce(Object... objects)
{
for(Object o : object)
if(o != null)
return o;
return null;
}