Java:如何避免三元运算符中的NPE,通常如何优雅地执行空检查?
昨天我不得不编写一段难看的代码,以便对对象的字段执行许多空检查,以避免三元运算符构造的NPE 有问题的代码:Java:如何避免三元运算符中的NPE,通常如何优雅地执行空检查?,java,nullpointerexception,null-check,Java,Nullpointerexception,Null Check,昨天我不得不编写一段难看的代码,以便对对象的字段执行许多空检查,以避免三元运算符构造的NPE 有问题的代码: ResourceThresholds rt = getThresholdsFromConfig(); Thresholds defaultPerContainer = getDefaultThresholds(); return new Thresholds((!rt.getCpu().equals("")) ? Long.parseLong(rt.getC
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就是这样工作的。
为什么我没有默认设置字段longcpu=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
来解析第一个变量中的NPE和三元运算符?因为这个代码段可以工作:!rt.getCpu()等于(“”)?Long.parseLong(rt.getCpu()):null
也就是说,如果我显式地将null
作为一个值,当条件满足时,我会得到null
一般来说,有什么优雅的Java8+方法可以解决这个问题吗
问题2:如何优化用于空检查的if-else构造
代码段中没有null
检查
最好实现一个简单的实用方法,在设置cpu
和内存时使用它,并在val
为null时使用Joda条件“”.equals(val)
来防止NPE
为避免取消装箱,请使用Long.valueOf
而不是返回原语Long
的Long.parseLong
:
公共静态Long getValue(字符串val,Long defaultValue){
返回“.equals(val)?默认值:Long.valueOf(val);
}
Long cpuVal=getValue(rt.getCpu(),defaultPerContainer.getCpu());
Long memory=getValue(rt.getMemory(),defaultPerContainer.getMemory());
还可以使用参数的提供者提供重载实用程序方法,然后将方法引用传递给它:
公共静态长getValue(供应商str、供应商deffal){
返回getValue(str.get(),deffal.get());//调用上面的实现
}
长cpuVal=getValue(rt::getCpu,defaultPerContainer::getCpu);
长内存=getValue(rt::getMemory,defaultPerContainer::getMemory);
问题是在三元表达式中A?B:C
,如果B
和C
都是兼容的数字类型,但一个是装箱对象,另一个是原语,大多数人会认为通过自动装箱原语,结果是装箱的
事实并非如此。三元运算符会取消绑定对象,因此它们都是基元,结果就是基元
这意味着以下内容是相同的:
long B=。。。;
长C=。。。;
长R=?B:C;
长R=(长)(…?B:(长)C);
结果是,如果C
为null,则得到NPE
解决此问题的一种方法是强制自动装箱B
:
Long R=?(长)B:C;
通过该更改,空C
值只需设置R=null
在问题中的例子中,B
是Long.parseLong(rt.getCpu())
,因此与其添加强制转换来强制自动装箱,不如使用代替
另外,使用isEmpty()
而不是equals(“”
),并且A
周围不需要括号
将代码更改为:
返回新阈值(!rt.getCpu().isEmpty()?Long.valueOf(rt.getCpu()):defaultPerContainer.getCpu(),
!rt.getMemory().isEmpty()?Long.valueOf(rt.getMemory()):defaultPerContainer.getMemory(),
/*为简洁起见省略*/);
@DawoodibnKareemyes@DawoodibnKareem我想我知道发生了什么。如果将?
和:
之间的部分更改为新长(rt.getCpu())
,您是否仍然会遇到问题?如果这解决了它,那是因为三元运算导致“true”和“false”部分被解释为long
而不是long
。我仍然得到NPE,逻辑上正确的第三个操作数应该是((long)defaultPerContainer.getCpu()。一般来说,我认为你不能投空?(defaultPerContainer.getCpu()返回null!)NullPointerException
当defaultValue=null
时--如果不解决实际问题,将代码移动到帮助器方法不会起任何作用。有关实际问题,请参阅。同意,通过避免拆箱来防止NPE。希望问题中的defaultPerContainer
不是空的。好奇:供应商的Supplier
版本有什么意义?如果defaultPerContainer
是空的,那么使用If
语句的问题修复将不起作用,所以情况并非如此。@Andreas,这只是一个可以使用函数代替值的示例