Java中如何获取第一个非空值?
Java 中是否存在与 SQL 的 COALESCE 函数等效的函数?也就是说,有没有办法返回几个变量的第一个非空值?
例如,
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)
但我想知道是否有任何内置的、可接受的函数来完成此操作。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
Apache Commons Lang 3
ObjectUtils.defaultIfNull(T, T)
或效率较低但具有更多潜在值:
ObjectUtils .firstNonNull(T...)
Java 8 Stream
Stream.of(T...).filter(Objects::nonNull).findFirst().orElse(null)
Apache Commons Lang 3
ObjectUtils.defaultIfNull(T, T)
or less efficient but for more potential values:
ObjectUtils.firstNonNull(T...)
Java 8 Stream
Stream.of(T...).filter(Objects::nonNull).findFirst().orElse(null)
不,没有。
您可以获得的最接近结果是:
出于高效原因,您可以按如下方式处理常见情况:
高效原因是每次调用该方法的
...
版本时都会发生数组分配。这对于一大堆物品来说可能会造成浪费,我怀疑这将是常见的用法。No, there isn't.
The closest you can get is:
For efficient reasons, you can handle the common cases as follows:
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.如果只有两个要测试的引用并且您使用的是 Java 8,则可以使用
如果导入 static 可选,则表达式还不错。
不幸的是,您的“几个变量”的情况不可能使用可选方法。相反,你可以使用:
If there are only two references to test and you are using Java 8, you could use
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:
如果只需要检查两个变量并且您使用的是 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).
根据 LES2 的答案,您可以通过调用重载函数来消除高效版本中的一些重复:
Following on from LES2's answer, you can eliminate some repetition in the efficient version, by calling the overloaded function:
这种情况需要一些预处理器。因为如果您编写一个选择第一个非空值的函数(静态方法),它将评估所有项目。如果某些项目是方法调用(可能是耗时的方法调用),则会出现问题。即使这些方法之前的任何项不为空,也会调用该方法。
应该使用像这样的一些函数
,但在编译成字节代码之前,应该有一个预处理器来找到这个“合并函数”的用法,并将其替换为像
更新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
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
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).
从 Java 9 开始,有内置的
Objects.requireNonNullElse
方法用于两个参数合并。这对我来说是最有用的。Since Java 9 there is builtin
Objects.requireNonNullElse
method for two parameter coalesce. That was the most useful for me.您可以尝试以下操作:
基于此响应
You can try this:
Based on this response
使用 Guava,您可以执行以下操作:
如果
a
和b
都为null
,则不会抛出 NPE。编辑:我错了,它确实抛出了 NPE。 Michal Čizmazia 评论的正确方法是:
With Guava you can do:
which doesn't throw NPE if both
a
andb
arenull
.EDIT: I was wrong, it does throw NPE. The correct way as commented by Michal Čizmazia is:
当您想避免评估某些昂贵的方法时,使用供应商怎么样?
像这样:
然后像这样使用它:
您还可以使用重载方法来进行带有两个、三个或四个参数的调用。
此外,您还可以使用流,如下所示:
How about using suppliers when you want to avoid evaluating some expensive method?
Like this:
And then using it like this:
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:
为了完整性,“多个变量”的情况确实是可能的,尽管一点也不优雅。例如,对于变量
o
、p
和q
:请注意使用
orElseGet()
来处理o
、p
和q
不是变量,而是表达式,要么成本高昂,要么具有不良副作用。在最一般的情况下,
coalesce(e[1],e[2],e[3],...,e[N])
这可能会生成过长的表达式。然而,如果我们试图进入一个没有
null
的世界,那么v[i]
很可能已经是Optional
类型了,而不是简单的String
。在这种情况下,或者在表达式的情况下:
此外,如果您还转向函数声明式样式,则
o
、p
和q 应该是
Supplier
类型,如下所示:然后整个
coalesce
简单地简化为o.get()
。更具体的示例:
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
, andq
:Please note the use of
orElseGet()
attending to the case thato
,p
, andq
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])
This can generate expressions excessively long. However, if we are trying to move to a world without
null
, thenv[i]
are most probably already of typeOptional<String>
, as opposed to simplyString
. In this case,or in the case of expressions:
Furthermore, if you are also moving to a functional-declarative style,
o
,p
, andq
should be of typeSupplier<String>
like in:And then the whole
coalesce
reduces simply too.get()
.For a more concrete example:
defaultAgeFromDatabase()
,ageFromDatabase()
, andageFromInput()
would already returnOptional<Integer>
, naturally.And then the
coalesce
becomeseffectiveAge.get()
or simplyeffectiveAge
if we are happy with aSupplier<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 aSupplier<T>
only one time, but lazily, as well as consistency in the definition ofOptional<T>
(i.e.Optional<T>
-Optional<T>
operators, or evenSupplier<Optional<T>>
).(与其他答案类似,但我想更详尽地描述 Guava 的
MoreObjects.firstNonNull()
、Apache Commons Lang 3ObjectUtils.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
。此方法要求其中一个对象为非空Apache Commons Lang 3
ObjectUtils.firstNonNull()
和defaultIfNull(T, T)
ObjectUtils.firstNonNull(T...)
另一方面,对空值的处理更加“宽松”。如果所有值都为 null,那么该方法将简单地返回null
。对于某些情况,这可能更好(只要调用代码正确处理null
返回值)。另请注意,这需要一个
T...
可变参数,因此它可以与两个以上的参数一起使用,这与其他选项不同。ObjectUtils.defaultIfNull(T, T)
方法也存在,并且具有类似的null
语义,但针对两者进行了稍微优化-参数场景。JDK
java.util.Objects.requireNonNullElse
和requireNonNullElseGet
方法Objects.requireNonNullElse(T, T)
具有以下语义。它与 GuavaMoreObjects.firstNonNull()
方法非常接近,它应该是该方法的直接替代品。最后,
Objects.requireNonNullElseGet(T obj,Suppliersupplier)
方法。如果创建回退值是一项较繁重的操作,而您希望在obj
为非null
时避免这种操作,那么它会很有用。TL;DR
null
,请使用Objects.requireNonNullElse(T, T)
null
并且您想要使用Supplier
进行后备(出于性能/GC 原因),请使用Objects.requireNonNullElseGet(T obj,Supplier ; 供应商)
null
并且 Apache Commons Lang 3 是可接受的依赖项,请使用ObjectUtils.defaultIfNull( T, T)
ObjectUtils.firstNonNull(T...)
但请注意,null
值可能会使用此方法潜入。您可能希望将结果包装在Objects.requireNonNullElse()
调用或其他一些null
保护中,以避免运行时出现 NPE。(Similar to other answers, but I wanted to more exhaustively describe the differences between Guava's
MoreObjects.firstNonNull()
, Apache Commons Lang 3ObjectUtils.firstNonNull()
and thejava.util.Objects.requireNonNullElse()
andrequireNonNullElseGet()
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-nullApache Commons Lang 3
ObjectUtils.firstNonNull()
anddefaultIfNull(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 returnsnull
. For some cases, this might be preferable (as long as the calling code handlesnull
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.The
ObjectUtils.defaultIfNull(T, T)
method also exists, and has similarnull
semantics, but is slightly more optimized for the two-parameter scenario.JDK
java.util.Objects.requireNonNullElse
andrequireNonNullElseGet
methodsObjects.requireNonNullElse(T, T)
has the following semantics. It matches the GuavaMoreObjects.firstNonNull()
method quite closely, it should be pretty much a drop-in replacement for that method.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 ifobj
is non-null
.TL;DR
null
, useObjects.requireNonNullElse(T, T)
null
and you want to use aSupplier
for the fallback (for performance/GC reasons), useObjects.requireNonNullElseGet(T obj, Supplier<? extends T> supplier)
null
and Apache Commons Lang 3 is an acceptable dependency, useObjectUtils.defaultIfNull(T, T)
ObjectUtils.firstNonNull(T...)
but please be aware thatnull
values can sneak through using this approach. You might want to wrap the result in aObjects.requireNonNullElse()
call or some othernull
-guard to avoid NPE at runtime.怎么样:
Java ArrayList 方便地允许空条目,并且无论要考虑的对象数量如何,该表达式都是一致的。 (在这种形式中,考虑的所有对象都必须属于同一类型。)
How about:
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.)