检查返回的值是否为 null,如果为 null,则用一个方法调用在一行中赋值

Java 中充斥着这样的语句:

if(cage.getChicken() != null) {
dinner = cage.getChicken();
} else {
dinner = getFreeRangeChicken();
}

在返回的对象被分配给 dinner之前,需要对 getChicken()进行两次调用。

这也可以写成这样一行:

dinner = cage.getChicken() != null? cage.getChicken() : getFreeRangeChicken();

但是,唉,还是有两个电话打到 getChicken()

当然,我们可以赋值一个局部变量,然后再次使用三元运算符赋值它,如果它不是 null 的话,但这是两行,并不那么漂亮:

FutureMeal chicken = cage.getChicken();
dinner = chicken != null? chicken : getFreeRangeChicken();

那么有没有办法说:

变量 var = 某个值,如果某个值不为空或其他值为空 价值;

我想我只是在这里讨论语法,在代码编译之后,从性能的角度来看,它可能不会对代码的编写方式产生太大的影响。

由于这是如此常见的代码,所以最好有一行程序来编写它。

其他语言有这个特性吗?

184575 次浏览
dinner = cage.getChicken();
if(dinner == null) dinner = getFreeRangeChicken();

or

if( (dinner = cage.getChicken() ) == null) dinner = getFreeRangeChicken();

Java lacks coalesce operator, so your code with an explicit temporary is your best choice for an assignment with a single call.

You can use the result variable as your temporary, like this:

dinner = ((dinner = cage.getChicken()) != null) ? dinner : getFreeRangeChicken();

This, however, is hard to read.

Using Java 1.8 you can use Optional

public class Main  {


public static void main(String[] args) {


//example call, the methods are just dumb templates, note they are static
FutureMeal meal = getChicken().orElse(getFreeRangeChicken());


//another possible way to call this having static methods is
FutureMeal meal = getChicken().orElseGet(Main::getFreeRangeChicken); //method reference


//or if you would use a Instance of Main and call getChicken and getFreeRangeChicken
// as nonstatic methods (assume static would be replaced with public for this)
Main m = new Main();
FutureMeal meal = m.getChicken().orElseGet(m::getFreeRangeChicken); //method reference


//or
FutureMeal meal = m.getChicken().orElse(m.getFreeRangeChicken()); //method call




}


static Optional<FutureMeal> getChicken(){


//instead of returning null, you would return Optional.empty()
//here I just return it to demonstrate
return Optional.empty();


//if you would return a valid object the following comment would be the code
//FutureMeal ret = new FutureMeal(); //your return object
//return Optional.of(ret);


}


static FutureMeal getFreeRangeChicken(){
return new FutureMeal();
}
}

You would implement a logic for getChicken to return either Optional.empty() instead of null, or Optional.of(myReturnObject), where myReturnObject is your chicken.

Then you can call getChicken() and if it would return Optional.empty() the orElse(fallback) would give you whatever the fallback would be, in your case the second method.

Alternatively in Java8 you can use Nullable or NotNull Annotations according to your need.

 public class TestingNullable {
@Nullable
public Color nullableMethod(){
//some code here
return color;
}


public void usingNullableMethod(){
// some code
Color color = nullableMethod();
// Introducing assurance of not-null resolves the problem
if (color != null) {
color.toString();
}
}
}

 public class TestingNullable {
public void foo(@NotNull Object param){
//some code here
}


...


public void callingNotNullMethod() {
//some code here
// the parameter value according to the explicit contract
// cannot be null
foo(null);
}
}

http://mindprod.com/jgloss/atnullable.html

Same principle as Loki's answer but shorter. Just keep in mind that shorter doesn't automatically mean better.

dinner = Optional.ofNullable(cage.getChicken())
.orElse(getFreerangeChicken());

Note: This usage of Optional is explicitly discouraged by the architects of the JDK and the designers of the Optional feature. You are allocating a fresh object and immediately throwing it away every time. But on the other hand it can be quite readable.

If you don't mind to use commons-lang you can use org.apache.commons.lang3.ObjectUtils#defaultIfNull

Your code would be:

dinner = ObjectUtils.defaultIfNull(cage.getChicken(),getFreeRangeChicken())

Use your own

public static <T> T defaultWhenNull(@Nullable T object, @NonNull T def) {
return (object == null) ? def : object;
}

Example:

defaultWhenNull(getNullableString(), "");

 

Advantages

  • Works if you don't develop in Java8
  • Works for android development with support for pre API 24 devices
  • Doesn't need an external library

Disadvantages

  • Always evaluates the default value (as oposed to cond ? nonNull() : notEvaluated())

    This could be circumvented by passing a Callable instead of a default value, but making it somewhat more complicated and less dynamic (e.g. if performance is an issue).

    By the way, you encounter the same disadvantage when using Optional.orElse() ;-)

Since Java 9 you have Objects#requireNonNullElse which does:

public static <T> T requireNonNullElse(T obj, T defaultObj) {
return (obj != null) ? obj : requireNonNull(defaultObj, "defaultObj");
}

Your code would be

dinner = Objects.requireNonNullElse(cage.getChicken(), getFreeRangeChicken());

Which is 1 line and calls getChicken() only once, so both requirements are satisfied.

Note that the second argument cannot be null as well; this method forces non-nullness of the returned value.

Consider also the alternative Objects#requireNonNullElseGet:

public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier)

which does not even evaluate the second argument if the first is not null, but does have the overhead of creating a Supplier.

You could use

Objects.requireNonNullElse(cage.getChicken(), getFreerangeChicken())

even nicer with static import:

import static java.util.Objects.requireNonNullElse;


requireNonNullElse(cage.getChicken(), getFreerangeChicken())