Java NullPointerException从何而来?

Java NullPointerException从何而来?,java,nullpointerexception,ternary-operator,Java,Nullpointerexception,Ternary Operator,我试图编写一个方法,将一个两位数的数字转换为2000+的数字,返回所有其他数字的原样,并在将null作为参数传递时返回null 此实现按预期工作 private Integer convertTo4Digits(Integer modelYear) { boolean isTwoDigit = modelYear != null && modelYear < 100; if (isTwoDigit) { return 2000 + model

我试图编写一个方法,将一个两位数的数字转换为2000+的数字,返回所有其他数字的原样,并在将null作为参数传递时返回null

此实现按预期工作

private Integer convertTo4Digits(Integer modelYear) {
    boolean isTwoDigit = modelYear != null && modelYear < 100;
    if (isTwoDigit) {
        return 2000 + modelYear;
    } else {
        return modelYear;
    }
}
private Integer convertto4数字(整型年份){
布尔值isTwoDigit=modelYear!=null&&modelYear<100;
如果(数字){
返回2000+车型年;
}否则{
回归模型年;
}
}
但是,当使用NULL调用时,这个函数在return语句中使用NPE失败

private Integer convertTo4Digits(Integer modelYear) {
    return (modelYear != null && modelYear < 100) ? (2000 + modelYear) : modelYear;
}
private Integer convertto4数字(整型年份){
返回(modelYear!=null&&modelYear<100)?(2000+modelYear):modelYear;
}
还是这是一只虫子?我将EclipseKeple与JDK1.7.0_04一起使用,噢,该死,这一个很有效(注意显式转换为整数):

(modelYear!=null&&modelYear<100)?(整数)(2000+车型年款):车型年款;
问题是:三元运算符的第一个分支决定了问题版本中运算符的结果类型:int


现在modelYear(null)被取消装箱,这导致NPE在再次装箱之前就被取消装箱。

我想答案可以在

如果第二个和第三个操作数中的一个是基元类型T,而另一个的类型是对T应用装箱转换(§5.1.7)的结果,则条件表达式的类型是T

因此,当第二个或第三个操作数是基元类型时,表达式的类型是基元类型。因此,如果您传递一个
null
引用,则将执行分支
:modelYear
。但是,由于一个操作数是基元,因此必须取消绑定。这导致了NPE

如果查看生成的字节码,也可以看到这一点

private convertTo4Digits(Ljava/lang/Integer;)Ljava/lang/Integer;
 L0
  LINENUMBER 46 L0
  ALOAD 1
  IFNULL L1
  ALOAD 1
  INVOKEVIRTUAL java/lang/Integer.intValue()I
  BIPUSH 100
  IF_ICMPGE L1
  SIPUSH 2000
  ALOAD 1
  INVOKEVIRTUAL java/lang/Integer.intValue()I
  IADD
  GOTO L2
 L1
  LINENUMBER 47 L1
  ALOAD 1
  INVOKEVIRTUAL java/lang/Integer.intValue()I
 L2
  LINENUMBER 46 L2
  INVOKESTATIC java/lang/Integer.valueOf(I)Ljava/lang/Integer;
  ARETURN 
您自己的答案解决了这个问题,因为您正在将第二个操作数强制转换为
Integer

(modelYear != null && modelYear < 100) ? (Integer) (2000 + modelYear) : modelYear;
(modelYear!=null&&modelYear<100)?(整数)(2000+车型年款):车型年款;

因此,第二个或第三个操作数都不是基元类型。因此,我在上面发布的JLS规则没有应用,NPE也没有了。

也许问题应该改为
为什么三元运算符会导致NullPointerException?
更具解释性
(modelYear != null && modelYear < 100) ? (Integer) (2000 + modelYear) : modelYear;