可以从null转换为int吗?

Gio*_*gio 53 java

我知道当我读到这个答案时,我会发现我忽略了一些在我眼前的东西.但我花了最后30分钟试图弄清楚自己没有结果.

所以,我在Java 6中编写了一个程序,并发现了一些(对我来说)奇怪的功能.为了尝试隔离它,我做了两个小例子.我首先尝试了以下方法:

private static int foo()
{
    return null;
}
Run Code Online (Sandbox Code Playgroud)

并且编译器拒绝它:类型不匹配:无法从null转换为int.

这对我很好,它尊重我熟悉的Java语义.然后我尝试了以下内容:

private static Integer foo(int x)
{
    if (x < 0)
    {
        return null;
    }
    else
    {
        return new Integer(x);
    }
}

private static int bar(int x)
{
    Integer y = foo(x);

    return y == null ? null : y.intValue();
}

private static void runTest()
{
    for (int index = 2; index > -2; index--)
    {
        System.out.println("bar(" + index + ") = " + bar(index));
    }
}
Run Code Online (Sandbox Code Playgroud)

编译没有错误!但是,在我看来,行中应该存在类型转换错误

    return y == null ? null : y.intValue();
Run Code Online (Sandbox Code Playgroud)

如果我运行程序,我得到以下输出:

bar(2) = 2
bar(1) = 1
bar(0) = 0
Exception in thread "main" java.lang.NullPointerException
    at Test.bar(Test.java:23)
    at Test.runTest(Test.java:30)
    at Test.main(Test.java:36)
Run Code Online (Sandbox Code Playgroud)

你能解释一下这种行为吗?

更新

非常感谢您提供的许多澄清答案.我有点担心,因为这个例子不符合我的直觉.令我不安的一件事是null被转换为int并且我想知道结果会是什么:0喜欢在C++中?那会很奇怪.很好,在运行时无法进行转换(空指针异常).

Jes*_*per 61

我们来看看这一行:

return y == null ? null : y.intValue();
Run Code Online (Sandbox Code Playgroud)

? :声明中,两者:必须具有相同的类型.在这种情况下,Java将使其具有类型Integer.一种Integer可能是null,所以左侧是确定的.表达式y.intValue()是类型的int,但是Java会自动将其设置为Integer(注意,您也可以编写y一个可以保存此autobox的文件).

现在,结果必须再次取消装箱int,因为方法的返回类型是int.如果你打开Integer那个null,你会得到一个NullPointerException.

注意:Java语言规范的第15.25段解释了关于? :条件运算符的类型转换的确切规则.

  • +1,这对我来说现在有意义了.为什么编译器不允许第一次测试,`int foo(){return null; 在这种情况下,再次,它应该将`null`自动放到`Integer`?或者,我想我的问题换句话说,为什么它选择将三元运算中的字段自动装箱为"整数"并且不将它们作为原语?这个决定在哪里? (2认同)

mic*_*lak 17

Guava有一个非常优雅的解决方案MoreObjects.firstNonNull:

Integer someNullInt = null;
int myInt = MoreObjects.firstNonNull(someNullInt, 0);
Run Code Online (Sandbox Code Playgroud)


Kal*_*Kal 6

返回类型的类型由Java在这里推断.那就是问题..

http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.25

这是实际问题 -

如果第二个和第三个操作数之一是null类型而另一个操作数的类型是引用类型,则条件表达式的类型是该引用类型.

所以,基本上编译器会将条件表达式的返回类型推断为Integer,这就是为什么它允许您成功编译.

编辑:请参阅评论中的规则


Has*_*ori 5

如果您的项目中没有Guava,但已经使用了Apache Commons,则可以将Apache Lang3与其ObjectUtils类一起使用.

用法与番石榴基本相同:

Integer number = null;
int notNull = ObjectUtils.firstNonNull(number, 0);
Run Code Online (Sandbox Code Playgroud)

请注意,Guava库中的此方法比Apache中的方法更快.这是我刚在笔记本电脑(Core i7-7500U 2.7 GHz),Oracle Java 8,多次运行,JVM预热,结果平均的简短比较:

??????????????????????????????????????????????
? Library/Runs ? 1000 ? 1mln ? 100mln ? 1bln ?
??????????????????????????????????????????????
? Apache       ?    1 ?   30 ?    782 ? 9981 ?
? Guava        ?    1 ?   22 ?    120 ?  828 ?
??????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

结果以毫秒为单位.我不认为你经常需要运行这种方法数十亿次,但是,进行性能比较总是好的