Java:如何避免三元运算符中的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

昨天我不得不编写一段难看的代码,以便对对象的字段执行许多空检查,以避免三元运算符构造的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就是这样工作的。 为什么我没有默认设置字段
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,这只是一个可以使用函数代替值的示例