Java 爪哇“?” 用于检查 null 的运算符 - 它是什么?(不是三元!)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4390141/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java "?" Operator for checking null - What is it? (Not Ternary!)
提问by Erty Seidohl
I was reading an article linked from a slashdot story, and came across this little tidbit:
我正在阅读一篇从 slashdot 故事链接的文章,并发现了这个小花絮:
Take the latest version of Java, which tries to make null-pointer checking easier by offering shorthand syntax for the endless pointer testing. Just adding a question mark to each method invocation automatically includes a test for null pointers, replacing a rat's nest of if-then statements, such as:
public String getPostcode(Person person) { String ans= null; if (person != null) { Name nm= person.getName(); if (nm!= null) { ans= nm.getPostcode(); } } return ans }
With this:
public String getFirstName(Person person) { return person?.getName()?.getGivenName(); }
以最新版本的 Java 为例,它试图通过为无休止的指针测试提供速记语法来简化空指针检查。只需在每个方法调用中添加一个问号,就会自动包含对空指针的测试,从而取代一堆 if-then 语句,例如:
public String getPostcode(Person person) { String ans= null; if (person != null) { Name nm= person.getName(); if (nm!= null) { ans= nm.getPostcode(); } } return ans }
有了这个:
public String getFirstName(Person person) { return person?.getName()?.getGivenName(); }
I've scoured the internet (okay, I spent at least 15 minutes googling variations on "java question mark") and got nothing. So, my question: is there any official documentation on this? I found that C# has a similar operator (the "??" operator), but I'd like to get the documentation for the language I'm working in. Or, is this just a use of the ternary operator that I've never seen before.
我搜索了互联网(好吧,我花了至少 15 分钟在“java 问号”上搜索变体)却一无所获。所以,我的问题:是否有任何官方文件?我发现 C# 有一个类似的运算符(“??”运算符),但我想获取我正在使用的语言的文档。或者,这只是我使用的三元运算符的使用从未见过。
Thanks!
谢谢!
EDIT: Link to the article: http://infoworld.com/d/developer-world/12-programming-mistakes-avoid-292
编辑:文章链接:http: //infoworld.com/d/developer-world/12-programming-mistakes-avoid-292
采纳答案by ataylor
The original idea comes from groovy. It was proposed for Java 7 as part of Project Coin: https://wiki.openjdk.java.net/display/Coin/2009+Proposals+TOC(Elvis and Other Null-Safe Operators), but hasn't been accepted yet.
最初的想法来自groovy。它被提议用于 Java 7 作为 Project Coin 的一部分:https: //wiki.openjdk.java.net/display/Coin/2009+Proposals+TOC(Elvis 和其他 Null-Safe Operators),但尚未被接受.
The related Elvis operator ?: was proposed to make x ?: y
shorthand for x != null ? x : y
, especially useful when x is a complex expression.
相关的 Elvis 运算符 ?: 被提议x ?: y
用作 的简写x != null ? x : y
,当 x 是一个复杂的表达式时特别有用。
回答by ColinD
This syntax does not exist in Java, nor is it slated to be included in any of the upcoming versions that I know of.
这种语法在 Java 中不存在,也不打算包含在我所知道的任何即将推出的版本中。
回答by Andrzej Doyle
That's actually Groovy's safe-dereference operator. You can't use it in pure Java (sadly), so that post is simply wrong (or more likely slightly misleading, if it's claiming Groovy to be the "latest version of Java").
这实际上是Groovy 的安全取消引用 operator。您不能在纯 Java 中使用它(遗憾的是),因此该帖子完全是错误的(或者更可能是稍微误导,如果它声称 Groovy 是“Java 的最新版本”)。
回答by PaulJWilliams
There was a proposal for it in Java 7, but it was rejected:
在 Java 7 中有一个提案,但被拒绝了:
回答by Darron
See: https://blogs.oracle.com/darcy/project-coin:-the-final-five-or-so(specifically "Elvis and other null safe operators").
请参阅:https: //blogs.oracle.com/darcy/project-coin: -the-final-five-or- so(特别是“猫王和其他空安全运算符”)。
The result is that this feature was considered for Java 7, but was not included.
结果是 Java 7 考虑了此功能,但未包含在内。
回答by KeithS
I'm not sure this would even work; if, say, the person reference was null, what would the runtime replace it with? A new Person? That would require the Person to have some default initialization that you'd expect in this case. You may avoid null reference exceptions but you'd still get unpredictable behavior if you didn't plan for these types of setups.
我不确定这是否可行;例如,如果 person 引用为空,运行时会用什么替换它?一个新人?这将要求 Person 具有您在这种情况下期望的一些默认初始化。您可以避免空引用异常,但如果您没有计划这些类型的设置,您仍然会遇到不可预测的行为。
The ?? operator in C# might be best termed the "coalesce" operator; you can chain several expressions and it will return the first that isn't null. Unfortunately, Java doesn't have it. I think the best you could do is use the ternary operator to perform null checks and evaluate an alternative to the entire expression if any member in the chain is null:
这 ??C# 中的运算符最好称为“合并”运算符;您可以链接多个表达式,它将返回第一个不为空的表达式。不幸的是,Java 没有它。我认为你能做的最好的事情是使用三元运算符来执行空检查,如果链中的任何成员为空,则评估整个表达式的替代方案:
return person == null ? ""
: person.getName() == null ? ""
: person.getName().getGivenName();
You could also use try-catch:
你也可以使用 try-catch:
try
{
return person.getName().getGivenName();
}
catch(NullReferenceException)
{
return "";
}
回答by Peter Lawrey
If this is not a performance issue for you, you can write
如果这对您来说不是性能问题,您可以编写
public String getFirstName(Person person) {
try {
return person.getName().getGivenName();
} catch (NullPointerException ignored) {
return null;
}
}
回答by H-MAN
There you have it, null-safe invocation in Java 8:
有了它,Java 8 中的空安全调用:
public void someMethod() {
String userName = nullIfAbsent(new Order(), t -> t.getAccount().getUser()
.getName());
}
static <T, R> R nullIfAbsent(T t, Function<T, R> funct) {
try {
return funct.apply(t);
} catch (NullPointerException e) {
return null;
}
}
回答by Helder Pereira
One way to workaround the lack of "?" operator using Java 8 without the overhead of try-catch (which could also hide a NullPointerException
originated elsewhere, as mentioned) is to create a class to "pipe" methods in a Java-8-Stream style.
解决缺少“?”的一种方法 在没有 try-catch 开销的情况下使用 Java 8 的操作符(NullPointerException
如前所述,它也可以隐藏其他地方的起源)是创建一个类来以 Java-8-Stream 样式“管道”方法。
public class Pipe<T> {
private T object;
private Pipe(T t) {
object = t;
}
public static<T> Pipe<T> of(T t) {
return new Pipe<>(t);
}
public <S> Pipe<S> after(Function<? super T, ? extends S> plumber) {
return new Pipe<>(object == null ? null : plumber.apply(object));
}
public T get() {
return object;
}
public T orElse(T other) {
return object == null ? other : object;
}
}
Then, the given example would become:
然后,给定的示例将变为:
public String getFirstName(Person person) {
return Pipe.of(person).after(Person::getName).after(Name::getGivenName).get();
}
[EDIT]
[编辑]
Upon further thought, I figured out that it is actually possible to achieve the same only using standard Java 8 classes:
经过进一步思考,我发现实际上仅使用标准 Java 8 类就可以实现相同的目标:
public String getFirstName(Person person) {
return Optional.ofNullable(person).map(Person::getName).map(Name::getGivenName).orElse(null);
}
In this case, it is even possible to choose a default value (like "<no first name>"
) instead of null
by passing it as parameter of orElse
.
在这种情况下,甚至可以选择一个默认值(如"<no first name>"
),而不是null
将其作为 的参数传递orElse
。
回答by Lii
It is possible to define util methods which solves this in an almost pretty way with Java 8 lambda.
可以定义 util 方法,使用 Java 8 lambda 以几乎漂亮的方式解决这个问题。
This is a variation of H-MANs solutionbut it uses overloaded methods with multiple arguments to handle multiple steps instead of catching NullPointerException
.
这是H-MANs 解决方案的一种变体,但它使用带有多个参数的重载方法来处理多个步骤而不是捕获NullPointerException
。
Even if I think this solution is kind of cool I think I prefer Helder Pereira'sseconds one since that doesn't require any util methods.
即使我认为这个解决方案有点酷,我认为我更喜欢Helder Pereira 的第二个解决方案,因为它不需要任何 util 方法。
void example() {
Entry entry = new Entry();
// This is the same as H-MANs solution
Person person = getNullsafe(entry, e -> e.getPerson());
// Get object in several steps
String givenName = getNullsafe(entry, e -> e.getPerson(), p -> p.getName(), n -> n.getGivenName());
// Call void methods
doNullsafe(entry, e -> e.getPerson(), p -> p.getName(), n -> n.nameIt());
}
/** Return result of call to f1 with o1 if it is non-null, otherwise return null. */
public static <R, T1> R getNullsafe(T1 o1, Function<T1, R> f1) {
if (o1 != null) return f1.apply(o1);
return null;
}
public static <R, T0, T1> R getNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, R> f2) {
return getNullsafe(getNullsafe(o0, f1), f2);
}
public static <R, T0, T1, T2> R getNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, T2> f2, Function<T2, R> f3) {
return getNullsafe(getNullsafe(o0, f1, f2), f3);
}
/** Call consumer f1 with o1 if it is non-null, otherwise do nothing. */
public static <T1> void doNullsafe(T1 o1, Consumer<T1> f1) {
if (o1 != null) f1.accept(o1);
}
public static <T0, T1> void doNullsafe(T0 o0, Function<T0, T1> f1, Consumer<T1> f2) {
doNullsafe(getNullsafe(o0, f1), f2);
}
public static <T0, T1, T2> void doNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, T2> f2, Consumer<T2> f3) {
doNullsafe(getNullsafe(o0, f1, f2), f3);
}
class Entry {
Person getPerson() { return null; }
}
class Person {
Name getName() { return null; }
}
class Name {
void nameIt() {}
String getGivenName() { return null; }
}