在Java的三元运算符中,即使表达式导致错误值,也可以评估第一个参数吗?

Met*_*002 13 java ternary-operator

我最近通过随机ad-hoc测试在我的代码中发现了一个不寻常的错误.所以,我为它做了一个测试用例.

这是我的测试用例:

 SampleRequest request = new SampleRequest();
    request.setA(null);
    request.setB(null);
    assertEquals(null, request.getAOrB());
Run Code Online (Sandbox Code Playgroud)

A和B被定义为java.lang.Integer类型,并具有直接的setter方法来将它们的值设置到请求中.

还涉及一个枚举.它有一个原始整数值,以及在此代码中使用的方法.我会在这里发布相关部分:

enum Swapper {
public int c;
Swapper findSwapperToUse(final int a) {
   for(Swapper swapper : values()) {
       if(swapper.c == a) {
          return swapper;
       }
   }
   return null;
}
}
Run Code Online (Sandbox Code Playgroud)

现在,这是令人困惑的方法.在该方法上调用测试方法会导致NPE,但是在方法的最后一行.

    public class SampleRequest {
    private Integer A;
    private Integer B;

    public void setA(final Integer A) {
        this.A = A;
    }

    public void setB(final Integer B) {
        this.B = B;
    }


public Integer getAOrB() {
    return A != null ? Swapper.findSwapperToUse(A).c
         : B;
}
}
Run Code Online (Sandbox Code Playgroud)

在测试中,A和B都设置为null.因此,A!= null返回false.但是,我在:B行的行号处得到NullPointerException.

我的猜测是由于某种原因,正在评估第一个表达式Swapper.findSwapperToUse(A).c,因此通过自动装箱调用A.intValue(),导致null值出现NullPointerException.通过调试,已知不调用findSwapperToUse().

但是,根据这个问题,这不应该发生: Java三元(即时)评估

未针对条件表达式的特定评估评估未选择的操作数表达式.

返回null(B)不会导致NullPointerException - 在这里返回null结果是完全正常的.

到底他妈发生了什么?

编辑:我忘了添加,我通过使用直接if语句来改变代码以避免这种情况 - 以下代码确实按预期工作:

public Integer getAOrB() {
    if(A != null) {
        return Swapper.findSwapperToUse(A).c;
    }
    return B;
}
Run Code Online (Sandbox Code Playgroud)

axt*_*avt 22

我猜这个问题是由于编译器推断出整个表达式的类型

A != null ? Swapper.findSwapperToUse(A).c : B
Run Code Online (Sandbox Code Playgroud)

作为int离型Swapper.c,并因此尝试应用解包转换到B.

以下是JLS的相关摘录,§15.25:

  • 否则,如果第二个和第三个操作数具有可转换(第5.1.8节)到数字类型的类型,则有几种情况:
    • ...
    • 否则,二进制数字提升(第5.6.2节)将应用于操作数类型,条件表达式的类型是第二个和第三个操作数的提升类型.请注意,二进制数字促销执行拆箱转换(第5.1.8节)和值集转换(第5.1.13节).

您可以通过添加以下强制转换来阻止它:

A != null ? (Integer) Swapper.findSwapperToUse(A).c : B
Run Code Online (Sandbox Code Playgroud)

  • :(应该有一个编译器标志来禁用自动装箱来捕捉这些东西. (2认同)