简体   繁体   English

从 null 转换为 int 可能吗?

[英]Conversion from null to int possible?

I know that when I read the answer to this I will see that I have overlooked something that was under my eyes.我知道,当我阅读此问题的答案时,我会发现我忽略了一些在我眼皮底下的东西。 But I have spent the last 30 minutes trying to figure it out myself with no result.但我花了最后 30 分钟试图自己弄清楚,但没有结果。

So, I was writing a program in Java 6 and discovered some (for me) strange feature.所以,我在 Java 6 中编写了一个程序,发现了一些(对我来说)奇怪的特性。 In order to try and isolate it, I have made two small examples.为了尝试和隔离它,我做了两个小例子。 I first tried the following method:我首先尝试了以下方法:

private static int foo()
{
    return null;
}

and the compiler refused it: Type mismatch: cannot convert from null to int.并且编译器拒绝了它:类型不匹配:无法从 null 转换为 int。

This is fine with me and it respects the Java semantics I am familiar with.这对我来说很好,它尊重我熟悉的 Java 语义。 Then I tried the following:然后我尝试了以下方法:

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));
    }
}

This compiles with no errors, But, in my opinion, there should be a type conversion error in the line这编译没有错误,但是,在我看来,该行应该有一个类型转换错误

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

If I run the program I get the following output:如果我运行程序,我会得到以下 output:

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)

Can you explain this behaviour?你能解释一下这种行为吗?

Update更新

Thank you very much for the many clarifying answers.非常感谢您提供的许多澄清答案。 I was a bit worried because this example did not correspond to my intuition.我有点担心,因为这个例子不符合我的直觉。 One thing that disturbed me was that a null was being converted to an int and I was wondering what the result would be: 0 like in C++?让我感到不安的一件事是 null 正在转换为 int,我想知道结果会是什么:0 就像 C++ 中的一样? That would hae been very strange.那会很奇怪。 Good that the conversion is not possible at runtime (null pointer exception).很好,在运行时无法进行转换(空指针异常)。

Let's look at the line:让我们看一下这条线:

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

In a ? :在一个? : ? : statement, both sides of the : must have the same type. ? :语句, :两边的类型必须相同。 In this case, Java is going to make it have the type Integer .在这种情况下, Java 将使其具有Integer类型。 An Integer can be null , so the left side is ok.一个Integer可以是null ,所以左边没问题。 The expression y.intValue() is of type int , but Java is going to auto-box this to Integer (note, you could just as well have written y which would have saved you this autobox).表达式y.intValue()的类型为int ,但 Java 将自动将其装箱为Integer (注意,您也可以编写y来保存此自动框)。

Now, the result has to be unboxed again to int , because the return type of the method is int .现在,必须再次将结果拆箱到int ,因为该方法的返回类型是int If you unbox an Integer that is null , you get a NullPointerException .如果您拆箱Integernull ,您会得到NullPointerException

Note: Paragraph 15.25 of the Java Language Specification explains the exact rules for type conversions with regard to the ? :注意:Java 语言规范的第 15.25 段解释了关于? : ? : conditional operator. ? :条件运算符。

Guava has a pretty elegant solution for this using MoreObjects.firstNonNull : Guava有一个非常优雅的解决方案,使用MoreObjects.firstNonNull

Integer someNullInt = null;
int myInt = MoreObjects.firstNonNull(someNullInt, 0);

The type of the return type is inferred by Java here.返回类型的类型由此处的 Java 推断。 That is the issue..就是这个问题。。

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

Here is the actual problem --这是实际的问题——

If one of the second and third operands is of the null type and the type of the other is a reference type, then the type of the conditional expression is that reference type.如果第二个和第三个操作数之一是 null 类型并且另一个的类型是引用类型,则条件表达式的类型是该引用类型。

So, basically the compiler infers the return type of the conditional expression to be Integer and thats why it allows you to compile successfully.因此,基本上编译器推断条件表达式的返回类型为 Integer,这就是它允许您成功编译的原因。

EDIT: See rules in comments编辑:查看评论中的规则

Just in case you don't have Guava in your project, but already using Apache Commons, you might utilize Apache Lang3 with its ObjectUtils class.万一您的项目中没有 Guava,但已经在使用 Apache Commons,您可以使用Apache Lang3及其ObjectUtils class。

The usage is basically the same as Guava:用法与Guava基本相同:

Integer number = null;
int notNull = ObjectUtils.firstNonNull(number, 0);

Note, that this method in Guava library works faster, than in Apache.请注意,Guava 库中的此方法比 Apache 中的方法运行得更快。 Here is a short comparison I just made on my laptop (Core i7-7500U 2.7 GHz), Oracle Java 8, multiple runs, JVM preheated, results are averaged:这是我刚刚在笔记本电脑(Core i7-7500U 2.7 GHz)上进行的简短比较,Oracle Java 8,多次运行,Z18B5A217C4DAD25662D3A05EDB0E 平均:

╔══════════════╦══════╦══════╦════════╦══════╗
║ Library/Runs ║ 1000 ║ 1mln ║ 100mln ║ 1bln ║
╠══════════════╬══════╬══════╬════════╬══════╣
║ Apache       ║    1 ║   30 ║    782 ║ 9981 ║
║ Guava        ║    1 ║   22 ║    120 ║  828 ║
╚══════════════╩══════╩══════╩════════╩══════╝

Results are in milliseconds.结果以毫秒为单位。 I don't think you often need to run this method for billions of times, but still, it is always good to have performance comparison我不认为你经常需要运行这种方法数十亿次,但是,进行性能比较总是好的

This illustrates a problematic difference between the way a human reads code and a compiler reads code.这说明了人类阅读代码的方式和编译器阅读代码的方式之间存在问题的差异。

When you see a ternary expression, it's very possible for you to mentally split it into two parts, in the style of an if / else statement:看到一个三元表达式时,你很可能会在心里把它分成两部分, if / else语句一样:

if (y == null)
    return null;
else
    return y.intValue();

You can see that this is invalid, as it results in a possible branch where a method defined to return an int is actually returning null (illegal.).可以看到这是无效的,因为它会导致一个可能的分支,其中定义为返回int的方法实际上返回null (非法。)。

What the compiler sees is an expression , which must have a type.编译器看到的是一个表达式,它必须有一个类型。 It notes that the ternary operation includes a null on one side and an int on the other;它注意到三元操作包括一侧的null和另一侧的int due to Java's autoboxing behavior, it then comes up with a "best guess" (my term, not Java's) as to what the expression's type is: Integer (this is fair: it's the only type which could legally be null or a boxed int ).由于 Java 的自动装箱行为,它会得出一个“最佳猜测”(我的术语,而不是 Java 的)关于表达式的类型是什么: Integer (这是公平的:它是合法的唯一类型null或装箱的int )。

Since the method is supposed to return an int , this is fine from the compiler's perspective: the expression being returned evaluates to an Integer , which can be unboxed automatically.由于该方法应该返回一个int ,因此从编译器的角度来看这很好:返回的表达式的计算结果为Integer ,可以自动拆箱。

The problem with autounboxing null values can be really annoying.自动拆箱null值的问题可能真的很烦人。 In your example it's a combination of ternary operator result type inferring and autounboxing (the JLS should be consulted why it behaves like that)在您的示例中,它是三元运算符结果类型推断和自动拆箱的组合(应咨询 JLS 为什么它的行为如此)

But generally, you should try to avoid using wrapper types.但通常,您应该尽量避免使用包装器类型。 Use int instead of Integer .使用int代替Integer If you need a special value meaning "no result", then you can use Integer.MAX_VALUE for example.如果您需要一个表示“无结果”的特殊值,则可以使用Integer.MAX_VALUE例如。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM