Java“?”运算符用于检查null – 它是什么? (不是三元!)

我正在阅读一篇关于Slashdot故事的文章,并且遇到了这个小琐事:

采取最新版本的Java,通过为无穷指针testing提供简化语法,试图使空指针检查更容易。 只需在每个方法调用中添加一个问号,就会自动包含对空指针的testing,replace老鼠的if-then语句嵌套,例如:

     public String getPostcode(Person person){
       String ans = null;
       if(person!= null){
        名称nm = person.getName();
         if(nm!= null){
           ans = nm.getPostcode();
         }
       }
      返回
     } 

有了这个:

 public String getFirstName(Person person){
      返回person?.getName()?。getGivenName();
     } 

我search了互联网(好吧,我花了至less15分钟search“java问号”的变体),什么都没有。 所以,我的问题是:有没有这方面的官方文件? 我发现C#有一个类似的操作符(“?”操作符),但是我想获取我正在使用的语言的文档。或者,这只是使用三元运算符从未见过。

谢谢!

编辑:链接到文章: http : //infoworld.com/d/developer-world/12-programming-mistakes-avoid-292

最初的想法来自groovy。 它被提议用于Java 7作为项目硬币的一部分: https : //wiki.openjdk.java.net/display/Coin/2009+Proposals+TOC (Elvis和其他Null-Safe运营商),但尚未被接受。

相关的Elvis算子?:被提出来使x ?: y简写为x != null ? x : y x != null ? x : y ,当x是复杂expression式时特别有用。

这个语法在Java中不存在,它也不包含在我所知的任何即将发布的版本中。

在Java 7中有一个提议,但是被拒绝了:

http://tech.puredanger.com/java7/#null

解决缺乏“?”的一种方法 运算符使用Java 8而没有try-catch的开销(如上所述,它也可以隐藏起源于其他地方的NullPointerException )是以Java-8-Stream风格创build一个“pipe道”方法的类。

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

那么,给出的例子就会变成:

 public String getFirstName(Person person) { return Pipe.of(person).after(Person::getName).after(Name::getGivenName).get(); } 

[编辑]

进一步思考后,我发现实际上只有使用标准的Java 8类才能达到同样的效果:

 public String getFirstName(Person person) { return Optional.ofNullable(person).map(Person::getName).map(Name::getGivenName).orElse(null); } 

在这种情况下,通过传递参数orElse ,甚至可以select一个默认值(比如"<no first name>" )而不是null

请参阅: https : //blogs.oracle.com/darcy/project-coin : -the- final-five-or- so (特别是“猫王和其他空安全运营商”)。

结果是这个function被考虑用于Java 7,但没有被包括在内。

这实际上是Groovy的安全解引用操作符 。 你不能在纯Java中使用它(可悲),所以post是完全错误的(或者如果声称Groovy是“最新版本的Java”,那么更可能有些误导性)。

Java 8 lambda几乎可以定义util方法来解决这个问题。

这是H-MAN解决scheme的变体,但是它使用重载方法和多个参数来处理多个步骤,而不是捕获NullPointerException

即使我认为这个解决scheme有点酷,我想我更喜欢Helder Pereira的第二个解决scheme,因为它不需要任何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; } } 

我不确定这样做会不会有效 如果说人的引用是空的,那么运行时会用什么replace呢? 一个新的人? 这就需要Person在这种情况下有一些默认的初始化。 您可以避免空引用exception,但是如果您没有计划这些types的设置,您仍然会得到不可预知的行为。

?? C#中的运算符可能被称为“合并”运算符。 你可以链接几个expression式,它会返回非空的第一个。 不幸的是,Java没有它。 我认为最好的办法是使用三元运算符来执行空检查,如果链中的任何成员为空,则评估整个expression式的替代:

 return person == null ? "" : person.getName() == null ? "" : person.getName().getGivenName(); 

你也可以使用try-catch:

 try { return person.getName().getGivenName(); } catch(NullReferenceException) { return ""; } 

在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; } } 

如果有人正在寻找旧的Java版本的替代品,你可以试试这个我写道:

 /** * Strong typed Lambda to return NULL or DEFAULT VALUES instead of runtime errors. * if you override the defaultValue method, if the execution result was null it will be used in place * * * Sample: * * It won't throw a NullPointerException but null. * <pre> * {@code * new RuntimeExceptionHandlerLambda<String> () { * @Override * public String evaluate() { * String x = null; * return x.trim(); * } * }.get(); * } * <pre> * * * @author Robson_Farias * */ public abstract class RuntimeExceptionHandlerLambda<T> { private T result; private RuntimeException exception; public abstract T evaluate(); public RuntimeException getException() { return exception; } public boolean hasException() { return exception != null; } public T defaultValue() { return result; } public T get() { try { result = evaluate(); } catch (RuntimeException runtimeException) { exception = runtimeException; } return result == null ? defaultValue() : result; } } 

如果这不是你的性能问题,你可以写

 public String getFirstName(Person person) { try { return person.getName().getGivenName(); } catch (NullPointerException ignored) { return null; } }