检查返回值是否不为 null,如果是,则通过一次方法调用在一行中分配它
Check if returned value is not null and if so assign it, in one line, with one method call
Java 到处都是这样的语句:
if(cage.getChicken() != null) {
dinner = cage.getChicken();
} else {
dinner = getFreeRangeChicken();
}
在将返回的对象分配给 dinner
之前需要两次调用 getChicken()
。
也可以这样写成一行:
dinner = cage.getChicken() != null? cage.getChicken() : getFreeRangeChicken();
但是仍然有两次调用getChicken()
。
当然我们可以分配一个局部变量然后再次使用三元运算符来分配它,如果它不为空,但这是两行并且不太漂亮:
FutureMeal chicken = cage.getChicken();
dinner = chicken != null? chicken : getFreeRangeChicken();
那么有什么办法可以说:
Variable var = some value if some value is not null OR some other
value;
而且我想我在这里只是在谈论语法,在编译代码之后,代码的编写方式在性能方面可能没有太大区别。
因为这是如此常见的代码,所以有一个单行代码来编写它会很棒。
其他语言有这个功能吗?
dinner = cage.getChicken();
if(dinner == null) dinner = getFreeRangeChicken();
或
if( (dinner = cage.getChicken() ) == null) dinner = getFreeRangeChicken();
Java 缺少合并运算符,因此带有显式临时变量的代码是一次调用赋值的最佳选择。
您可以将结果变量用作临时变量,如下所示:
dinner = ((dinner = cage.getChicken()) != null) ? dinner : 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
到 return 的逻辑,或者 Optional.empty()
而不是 null,或者 Optional.of(myReturnObject)
,其中 myReturnObject
是您的 chicken
.
然后你可以调用 getChicken()
如果它会 return Optional.empty()
那么 orElse(fallback)
会给你任何后备方法,在你的情况下是第二种方法。
或者在 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);
}
}
原理与 Loki 的回答相同,但更短。请记住,更短并不意味着更好。
dinner = Optional.ofNullable(cage.getChicken())
.orElse(getFreerangeChicken());
注意:Optional
的这种用法受到 JDK 的架构师和可选功能的设计者的明确反对。您每次都分配一个新对象并立即将其丢弃。但另一方面,它的可读性也很好。
如果您还没有使用 java 1.8,并且您不介意使用 commons-lang,您可以使用 org.apache.commons.lang3.ObjectUtils#defaultIfNull
您的代码将是:
dinner = ObjectUtils.defaultIfNull(cage.getChicken(),getFreeRangeChicken())
使用你自己的
public static <T> T defaultWhenNull(@Nullable T object, @NonNull T def) {
return (object == null) ? def : object;
}
示例:
defaultWhenNull(getNullableString(), "");
优势
- 如果您 不在 Java8
中开发,则有效
- 适用于 android 开发,支持 pre API 24 设备
- 不需要外部库
缺点
总是计算 default value
(相对于 cond ? nonNull() : notEvaluated()
)
这可以通过传递 Callable 而不是默认值来规避,但会使其更加复杂且动态性降低(例如,如果性能是一个问题)。
顺便说一下,你在使用 Optional.orElse()
时遇到了同样的缺点 ;-)
因为 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
.
的开销
你可以使用
Objects.requireNonNullElse(cage.getChicken(), getFreerangeChicken())
静态导入更好:
import static java.util.Objects.requireNonNullElse;
requireNonNullElse(cage.getChicken(), getFreerangeChicken())
Java 到处都是这样的语句:
if(cage.getChicken() != null) {
dinner = cage.getChicken();
} else {
dinner = getFreeRangeChicken();
}
在将返回的对象分配给 dinner
之前需要两次调用 getChicken()
。
也可以这样写成一行:
dinner = cage.getChicken() != null? cage.getChicken() : getFreeRangeChicken();
但是仍然有两次调用getChicken()
。
当然我们可以分配一个局部变量然后再次使用三元运算符来分配它,如果它不为空,但这是两行并且不太漂亮:
FutureMeal chicken = cage.getChicken();
dinner = chicken != null? chicken : getFreeRangeChicken();
那么有什么办法可以说:
Variable var = some value if some value is not null OR some other value;
而且我想我在这里只是在谈论语法,在编译代码之后,代码的编写方式在性能方面可能没有太大区别。
因为这是如此常见的代码,所以有一个单行代码来编写它会很棒。
其他语言有这个功能吗?
dinner = cage.getChicken();
if(dinner == null) dinner = getFreeRangeChicken();
或
if( (dinner = cage.getChicken() ) == null) dinner = getFreeRangeChicken();
Java 缺少合并运算符,因此带有显式临时变量的代码是一次调用赋值的最佳选择。
您可以将结果变量用作临时变量,如下所示:
dinner = ((dinner = cage.getChicken()) != null) ? dinner : 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
到 return 的逻辑,或者 Optional.empty()
而不是 null,或者 Optional.of(myReturnObject)
,其中 myReturnObject
是您的 chicken
.
然后你可以调用 getChicken()
如果它会 return Optional.empty()
那么 orElse(fallback)
会给你任何后备方法,在你的情况下是第二种方法。
或者在 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);
}
}
原理与 Loki 的回答相同,但更短。请记住,更短并不意味着更好。
dinner = Optional.ofNullable(cage.getChicken())
.orElse(getFreerangeChicken());
注意:Optional
的这种用法受到 JDK 的架构师和可选功能的设计者的明确反对。您每次都分配一个新对象并立即将其丢弃。但另一方面,它的可读性也很好。
如果您还没有使用 java 1.8,并且您不介意使用 commons-lang,您可以使用 org.apache.commons.lang3.ObjectUtils#defaultIfNull
您的代码将是:
dinner = ObjectUtils.defaultIfNull(cage.getChicken(),getFreeRangeChicken())
使用你自己的
public static <T> T defaultWhenNull(@Nullable T object, @NonNull T def) {
return (object == null) ? def : object;
}
示例:
defaultWhenNull(getNullableString(), "");
优势
- 如果您 不在 Java8 中开发,则有效
- 适用于 android 开发,支持 pre API 24 设备
- 不需要外部库
缺点
总是计算
default value
(相对于cond ? nonNull() : notEvaluated()
)这可以通过传递 Callable 而不是默认值来规避,但会使其更加复杂且动态性降低(例如,如果性能是一个问题)。
顺便说一下,你在使用
Optional.orElse()
时遇到了同样的缺点 ;-)
因为 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
.
你可以使用
Objects.requireNonNullElse(cage.getChicken(), getFreerangeChicken())
静态导入更好:
import static java.util.Objects.requireNonNullElse;
requireNonNullElse(cage.getChicken(), getFreerangeChicken())