Java”?“检查空值的操作符——它是什么?”(不是三元!)

时间:2021-10-02 01:14:38

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:

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

With this:

用这个:


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-编程错误- avoi-292

13 个解决方案

#1


65  

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+ proposal +TOC (Elvis和其他Null-Safe操作符),但是还没有被接受。

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是一个复杂的表达式时。

#2


48  

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中不存在,也不打算包含在我所知道的任何即将发布的版本中。

#3


16  

There was a proposal for it in Java 7, but it was rejected:

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

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

http://tech.puredanger.com/java7/零

#4


13  

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.

解决使用Java 8的“?”操作符缺乏的一种方法是创建一个类,以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.

在这种情况下,甚至可以选择默认值(如“ ”)而不是null,将其作为orElse的参数传递。

#5


7  

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/projectcoin:-the-final-five左右(特别是“Elvis and other null safe operators”)。

The result is that this feature was considered for Java 7, but was not included.

结果是这个特性被考虑为Java 7,但不包括在内。

#6


6  

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的安全取消引用操作符。您不能在纯Java中使用它(遗憾的是),因此这篇文章完全是错误的(或者更有可能具有误导性,如果它声称Groovy是“Java的最新版本”)。

#7


2  

It is possible to define util methods which solves this in an almost pretty way with Java 8 lambda.

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

This is a variation of H-MANs solution but 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's seconds one since that doesn't require any util methods.

即使我觉得这个解决方案很酷,我还是更喜欢海德尔·佩雷拉的秒1,因为它不需要任何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; }
}

#8


1  

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引用为空,运行时将用什么来替换它?一个新的人吗?这就要求这个人有一些默认的初始化,这是你在这种情况下所期望的。您可能避免了空引用异常,但是如果不针对这些类型的设置进行计划,您仍然会得到不可预测的行为。

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

#9


0  

There you have it, null-safe invocation in Java 8:

这就是Java 8中的null-safe调用:

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

#10


0  

If someone is looking for an alternative for old java versions, you can try this one I wrote:

如果有人在寻找旧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;
    }

}

#11


0  

You can test the code which you have provided and it will give syntax error.So, it is not supported in Java. Groovy does support it and it was proposed for Java 7 (but never got included).

您可以测试所提供的代码,并且会给出语法错误。因此,Java不支持它。Groovy确实支持它,它是为Java 7(但从未包含在内)而提出的。

However, you can use the Optional provided in Java 8. This might help you in achieving something on similar line. https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html

但是,您可以使用Java 8中提供的可选选项。这可能会帮助你在类似的事情上取得成功。https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html http://www.oracle.com/technetwork/articles/java/java8 -可选2175753. - html

Example Code for Optional

示例代码的可选

#12


0  

Java does not have the exact syntax but as of JDK-8, we have the Optional API with various methods at our disposal. So, the C# version with the use of null conditional operator:

Java没有确切的语法,但是对于JDK-8,我们有可选的API,可以使用各种方法。因此,c#版本使用null条件运算符:

return person?.getName()?.getGivenName(); 

can be written as follows in Java with the Optional API:

可使用可选的API在Java中编写如下:

 return Optional.ofNullable(person)
                .map(e -> e.getName())
                .map(e -> e.getGivenName())
                .orElse(null);

if any of person, getName or getGivenName is null then null is returned.

如果任何人、getName或getGivenName都为空,则返回null。

#13


-3  

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

#1


65  

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+ proposal +TOC (Elvis和其他Null-Safe操作符),但是还没有被接受。

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是一个复杂的表达式时。

#2


48  

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中不存在,也不打算包含在我所知道的任何即将发布的版本中。

#3


16  

There was a proposal for it in Java 7, but it was rejected:

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

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

http://tech.puredanger.com/java7/零

#4


13  

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.

解决使用Java 8的“?”操作符缺乏的一种方法是创建一个类,以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.

在这种情况下,甚至可以选择默认值(如“ ”)而不是null,将其作为orElse的参数传递。

#5


7  

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/projectcoin:-the-final-five左右(特别是“Elvis and other null safe operators”)。

The result is that this feature was considered for Java 7, but was not included.

结果是这个特性被考虑为Java 7,但不包括在内。

#6


6  

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的安全取消引用操作符。您不能在纯Java中使用它(遗憾的是),因此这篇文章完全是错误的(或者更有可能具有误导性,如果它声称Groovy是“Java的最新版本”)。

#7


2  

It is possible to define util methods which solves this in an almost pretty way with Java 8 lambda.

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

This is a variation of H-MANs solution but 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's seconds one since that doesn't require any util methods.

即使我觉得这个解决方案很酷,我还是更喜欢海德尔·佩雷拉的秒1,因为它不需要任何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; }
}

#8


1  

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引用为空,运行时将用什么来替换它?一个新的人吗?这就要求这个人有一些默认的初始化,这是你在这种情况下所期望的。您可能避免了空引用异常,但是如果不针对这些类型的设置进行计划,您仍然会得到不可预测的行为。

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

#9


0  

There you have it, null-safe invocation in Java 8:

这就是Java 8中的null-safe调用:

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

#10


0  

If someone is looking for an alternative for old java versions, you can try this one I wrote:

如果有人在寻找旧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;
    }

}

#11


0  

You can test the code which you have provided and it will give syntax error.So, it is not supported in Java. Groovy does support it and it was proposed for Java 7 (but never got included).

您可以测试所提供的代码,并且会给出语法错误。因此,Java不支持它。Groovy确实支持它,它是为Java 7(但从未包含在内)而提出的。

However, you can use the Optional provided in Java 8. This might help you in achieving something on similar line. https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html

但是,您可以使用Java 8中提供的可选选项。这可能会帮助你在类似的事情上取得成功。https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html http://www.oracle.com/technetwork/articles/java/java8 -可选2175753. - html

Example Code for Optional

示例代码的可选

#12


0  

Java does not have the exact syntax but as of JDK-8, we have the Optional API with various methods at our disposal. So, the C# version with the use of null conditional operator:

Java没有确切的语法,但是对于JDK-8,我们有可选的API,可以使用各种方法。因此,c#版本使用null条件运算符:

return person?.getName()?.getGivenName(); 

can be written as follows in Java with the Optional API:

可使用可选的API在Java中编写如下:

 return Optional.ofNullable(person)
                .map(e -> e.getName())
                .map(e -> e.getGivenName())
                .orElse(null);

if any of person, getName or getGivenName is null then null is returned.

如果任何人、getName或getGivenName都为空,则返回null。

#13


-3  

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