Java 中充斥着这样的语句:
if(cage.getChicken() != null) {
dinner = cage.getChicken();
} else {
dinner = getFreeRangeChicken();
}
需要两次调用
getChicken()
,然后才能将返回的对象分配给 dinner
。
这也可以写成一行,如下所示:
dinner = cage.getChicken() != null? cage.getChicken() : getFreeRangeChicken();
但是可惜还有两个电话打给
getChicken()
。
当然,我们可以分配一个局部变量,然后如果它不为空,则再次使用三元运算符来分配它,但这是两行,不太漂亮:
FutureMeal chicken = cage.getChicken();
dinner = chicken != null? chicken : getFreeRangeChicken();
那么有什么办法可以说:
变量 var = 某个值(如果某个值不为空或其他值) 值;
我想我在这里只是谈论语法,在代码编译之后,从性能角度来看代码的编写方式可能没有太大区别。
由于这是如此常见的代码,因此如果能用一行代码来编写它就太好了。
其他语言有这个功能吗?
与 Loki 的答案相同,但更短。请记住,更短并不意味着更好。
dinner = Optional.ofNullable(cage.getChicken())
.orElse(getFreerangeChicken());
注意:JDK 的架构师和可选功能的设计者明确不鼓励使用
Optional
。你每次都会分配一个新的对象并立即扔掉它。但另一方面,它的可读性也很高。
Java 缺乏合并运算符,因此具有显式临时值的代码是通过单次调用进行赋值的最佳选择。
您可以使用结果变量作为临时变量,如下所示:
dinner = ((dinner = cage.getChicken()) != null) ? dinner : getFreeRangeChicken();
然而,这很难读懂。
从 Java 9 开始,你有了 Objects#requireNonNullElse ,它的作用是:
public static <T> T requireNonNullElse(T obj, T defaultObj) {
return (obj != null) ? obj : requireNonNull(defaultObj, "defaultObj");
}
你的代码是
dinner = Objects.requireNonNullElse(cage.getChicken(), getFreeRangeChicken());
即 1 条线路,仅调用
getChicken()
一次,因此满足两个要求。
请注意,第二个参数也不能是
null
;此方法强制返回值非空。
还可以考虑替代方案 Objects#requireNonNullElseGet:
public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier)
如果第一个参数不是
null
,它甚至不会评估第二个参数,但确实有创建 Supplier
的开销。
如果您不介意使用commons-lang,您可以使用org.apache.commons.lang3.ObjectUtils#defaultIfNull
您的代码将是:
dinner = ObjectUtils.defaultIfNull(cage.getChicken(),getFreeRangeChicken())
使用Java 1.8,您可以使用
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();
}
}
您可以为
getChicken
实现一个逻辑,以返回 Optional.empty()
(而不是 null)或 Optional.of(myReturnObject)
,其中 myReturnObject
是您的 chicken
。
然后你可以调用
getChicken()
,如果它返回 Optional.empty()
orElse(fallback)
会给你任何后备,在你的情况下是第二种方法。
public static <T> T defaultWhenNull(@Nullable T object, @NonNull T def) {
return (object == null) ? def : object;
}
示例:
defaultWhenNull(getNullableString(), "");
始终评估
default value
(与 cond ? nonNull() : notEvaluated()
相对)
可以通过传递 Callable 而不是默认值来避免这种情况,但会使其更加复杂且动态性较差(例如,如果性能是一个问题)。
顺便说一句,您在使用时也会遇到同样的缺点
Optional.orElse()
;-)dinner = cage.getChicken();
if(dinner == null) dinner = getFreeRangeChicken();
或
if( (dinner = cage.getChicken() ) == null) dinner = getFreeRangeChicken();
你可以使用
Objects.requireNonNullElseGet(cage.getChicken(), () -> getFreerangeChicken())
静态导入效果更好:
import static java.util.Objects.requireNonNullElseGet;
requireNonNullElseGet(cage.getChicken(), () -> getFreerangeChicken())
简单地尝试复制列表,如果它引用 null,将触发 NullPointerException:
List<String> originalList = null;
List<String> copyList = new ArrayList(originalList);
相同 NullPointerException 如果我们使用更新的 API 来获取不可变列表:
List<String> originalList = null;
List<String> copyList = List.copyOf(originalList);
这就是我们可以控制拦截异常的好处。然而,如果原始列表引用 null,我们通常只想有一个空列表。这里有几个创建原始列表副本的示例。 如果原始列表为空,它将返回一个空列表,而不是抛出异常:
//List copied into immutable List
//Java 9+
copyList = List.copyOf(Objects.requireNonNullElse(originalList, List.of()));
//Java 8+
copyList = List.copyOf(Optional.ofNullable(originalList).orElse(List.of()));
//Copy provided within good old mutable ArrayList
//Java 9+
copyList = new ArrayList(Objects.requireNonNullElse(originalList, new ArrayList()));
//Java 8+
copyList = new ArrayList(Optional.ofNullable(originalList).orElse(new ArrayList()));
或者在 Java8 中,您可以根据需要使用 Nullable 或 NotNull 注解。
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);
}
}