Java: 如何在三元运算符中避免 NPE,通常如何优雅地执行 null 检查?
Java: how to avoid NPE in ternary operator, in general how to perform null-checks elegantly?
昨天我不得不写一段丑陋的代码,为了对对象的字段执行许多空检查,以避免三元运算符构造的 NPE。
有问题的代码:
ResourceThresholds rt = getThresholdsFromConfig();
Thresholds defaultPerContainer = getDefaultThresholds();
return new Thresholds((!rt.getCpu().equals("")) ? Long.parseLong(rt.getCpu()) : defaultPerContainer.getCpu(),
(!rt.getMemory().equals("")) ? Long.parseLong(rt.getMemory()) : defaultPerContainer.getMemory(),/*omitted for brevity*/);
我在 defaultPerContainer.getCpu()
上得到了 NPE,因为字段 cpu = null
。
这很好,Java 以它的方式工作。
为什么我不直接默认字段 Long cpu = 0L;
?因为我需要 null
值作为我们不设置任何值的指标。
这段特定代码的最终功能变体是:
Long cpuVal;
if (!rt.getCpu().equals("")) {
cpuVal = Long.parseLong(rt.getCpu());
} else {
cpuVal = defaultPerContainer.getCpu();
}
Long memory;
if (!rt.getMemory().equals("")) {
memory = Long.parseLong(rt.getMemory());
} else {
memory = defaultPerContainer.getMemory();
}
//... many similar if-elses that give me the desired value;
//which is really ugly, and I believe I am not the only one hitting this.
return new Thresholds(cpuVal, memory..);
这段代码可以正常工作,但它很丑!
问题 1:有人可以提示我是否可以找到使用 Optional<T>
的方法来解决带有三元运算符的第一个变体中的 NPE?因为这个片段有效:!rt.getCpu().equals("")) ? Long.parseLong(rt.getCpu()) : null
即如果我明确地将 null
作为一个值,当条件满足时我得到 null
。
一般来说,有什么优雅的 Java 8+ 方法来处理这个问题吗?
问题 2:您如何优化出色的 if-else 结构以进行空值检查?
- 代码段中没有
null
检查。
- 最好实现一个简单的实用方法,在设置
cpu
和memory
时使用它,如果val
是null
- 为了避免拆箱,使用
Long.valueOf
而不是 Long.parseLong
which returns primitive long
:
public static Long getValue(String val, Long defaultValue) {
return "".equals(val) ? defaultValue : Long.valueOf(val);
}
Long cpuVal = getValue(rt.getCpu(), defaultPerContainer.getCpu());
Long memory = getValue(rt.getMemory(), defaultPerContainer.getMemory());
也可以使用参数提供者提供重载实用程序方法,然后将方法引用传递给它:
public static Long getValue(Supplier<String> str, Supplier<Long> defVal) {
return getValue(str.get(), defVal.get()); // calling implementation above
}
Long cpuVal = getValue(rt::getCpu, defaultPerContainer::getCpu);
Long memory = getValue(rt::getMemory, defaultPerContainer::getMemory);
问题是在三元表达式A ? B : C
中,如果B
和C
都是兼容的数值类型,但是一个是盒装对象,另一个是 primitive,大多数人会认为结果是装箱的,通过自动装箱原语。
事实并非如此。三元运算符改为拆箱对象,因此它们都是原语,结果也是原语。
这意味着以下是相同的:
long B = ...;
Long C = ...;
Long R = ... ? B : C;
Long R = (Long) (... ? B : (long) C);
结果是,如果 C
为 null,则得到 NPE。
一种解决方法是强制自动装箱 B
:
Long R = ... ? (Long) B : C;
有了这个改变,空 C
值将简单地设置 R = null
.
在问题的情况下,B
是 Long.parseLong(rt.getCpu())
,因此不是添加强制转换来强制自动装箱,使用 long.valueOf(String s)
代替。
另外,不相关的,用isEmpty()
代替equals("")
,A
.
两边不需要括号
将代码更改为:
return new Thresholds(!rt.getCpu().isEmpty() ? Long.valueOf(rt.getCpu()) : defaultPerContainer.getCpu(),
!rt.getMemory().isEmpty() ? Long.valueOf(rt.getMemory()) : defaultPerContainer.getMemory(),
/*omitted for brevity*/);
昨天我不得不写一段丑陋的代码,为了对对象的字段执行许多空检查,以避免三元运算符构造的 NPE。
有问题的代码:
ResourceThresholds rt = getThresholdsFromConfig();
Thresholds defaultPerContainer = getDefaultThresholds();
return new Thresholds((!rt.getCpu().equals("")) ? Long.parseLong(rt.getCpu()) : defaultPerContainer.getCpu(),
(!rt.getMemory().equals("")) ? Long.parseLong(rt.getMemory()) : defaultPerContainer.getMemory(),/*omitted for brevity*/);
我在 defaultPerContainer.getCpu()
上得到了 NPE,因为字段 cpu = null
。
这很好,Java 以它的方式工作。
为什么我不直接默认字段 Long cpu = 0L;
?因为我需要 null
值作为我们不设置任何值的指标。
这段特定代码的最终功能变体是:
Long cpuVal;
if (!rt.getCpu().equals("")) {
cpuVal = Long.parseLong(rt.getCpu());
} else {
cpuVal = defaultPerContainer.getCpu();
}
Long memory;
if (!rt.getMemory().equals("")) {
memory = Long.parseLong(rt.getMemory());
} else {
memory = defaultPerContainer.getMemory();
}
//... many similar if-elses that give me the desired value;
//which is really ugly, and I believe I am not the only one hitting this.
return new Thresholds(cpuVal, memory..);
这段代码可以正常工作,但它很丑!
问题 1:有人可以提示我是否可以找到使用 Optional<T>
的方法来解决带有三元运算符的第一个变体中的 NPE?因为这个片段有效:!rt.getCpu().equals("")) ? Long.parseLong(rt.getCpu()) : null
即如果我明确地将 null
作为一个值,当条件满足时我得到 null
。
一般来说,有什么优雅的 Java 8+ 方法来处理这个问题吗?
问题 2:您如何优化出色的 if-else 结构以进行空值检查?
- 代码段中没有
null
检查。 - 最好实现一个简单的实用方法,在设置
cpu
和memory
时使用它,如果val
是null
- 为了避免拆箱,使用
Long.valueOf
而不是Long.parseLong
which returns primitivelong
:
public static Long getValue(String val, Long defaultValue) {
return "".equals(val) ? defaultValue : Long.valueOf(val);
}
Long cpuVal = getValue(rt.getCpu(), defaultPerContainer.getCpu());
Long memory = getValue(rt.getMemory(), defaultPerContainer.getMemory());
也可以使用参数提供者提供重载实用程序方法,然后将方法引用传递给它:
public static Long getValue(Supplier<String> str, Supplier<Long> defVal) {
return getValue(str.get(), defVal.get()); // calling implementation above
}
Long cpuVal = getValue(rt::getCpu, defaultPerContainer::getCpu);
Long memory = getValue(rt::getMemory, defaultPerContainer::getMemory);
问题是在三元表达式A ? B : C
中,如果B
和C
都是兼容的数值类型,但是一个是盒装对象,另一个是 primitive,大多数人会认为结果是装箱的,通过自动装箱原语。
事实并非如此。三元运算符改为拆箱对象,因此它们都是原语,结果也是原语。
这意味着以下是相同的:
long B = ...;
Long C = ...;
Long R = ... ? B : C;
Long R = (Long) (... ? B : (long) C);
结果是,如果 C
为 null,则得到 NPE。
一种解决方法是强制自动装箱 B
:
Long R = ... ? (Long) B : C;
有了这个改变,空 C
值将简单地设置 R = null
.
在问题的情况下,B
是 Long.parseLong(rt.getCpu())
,因此不是添加强制转换来强制自动装箱,使用 long.valueOf(String s)
代替。
另外,不相关的,用isEmpty()
代替equals("")
,A
.
将代码更改为:
return new Thresholds(!rt.getCpu().isEmpty() ? Long.valueOf(rt.getCpu()) : defaultPerContainer.getCpu(),
!rt.getMemory().isEmpty() ? Long.valueOf(rt.getMemory()) : defaultPerContainer.getMemory(),
/*omitted for brevity*/);