Java Deep

Pure Java, what else

Something you did not know about the ternary operator

Recently I had a little surprise. It started me compiling some Java class and it did not work the way I expected. This is not the surprise itself: this is just the way I live. Develop, debug, release cycles. So the development cycle started. I was looking to find a bug in my code and as I tightened the bug boundary it came down to a ternary operator. The following sample demonstrates the situation:

public class Bug{
    public static Number q(Number in) {
        return in instanceof Long ? 1L : 1.0;
    }
}

It was supposed to return a Long or a Double value of one, depending on the type of the argument. However the method returned a 1.0 Double.

I looked at the code generated by javac using the javap disassembler and I saw that the case is really the one I explained above:

public static java.lang.Number q(java.lang.Number);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0       
         1: instanceof    #2                  // class java/lang/Long
         4: ifeq          11
         7: dconst_1      
         8: goto          12
        11: dconst_1      
        12: invokestatic  #3                  // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
        15: areturn       

No matter what type the argument has, the code loads a constant Double on the operational stack executing the bytecode (dconst_1). This code is not good. But it does not mean that there is a bug in the javac compiler. This is not a bug, this is a feature.

The next thing I consulted was the Java language specification. You can read it from the URL http://docs.oracle.com/javase/specs/jls/se7/html/index.html and it talks about the ternary operator:

Otherwise, if the second and third operands have types that are convertible (§5.1.8) to numeric types, then there are several cases:

Otherwise, binary numeric promotion (§5.6.2) is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands.

In our case numeric promotion happens according to §5.6.2 :

If either operand is of type double, the other is converted to double.

It explains why this code above is useless. in situations like that use the good old ‘if’ ‘then’ ‘else’ construct.

Update

Recently Lukas Eder posted a similar article on his JOOQ blog worth following. This article is brief and highlights a different effect of the same issue.

One response to “Something you did not know about the ternary operator

  1. Tyborg October 10, 2013 at 10:07 am

    You can cast it to Number, and this will work well:
    return in instanceof Long ? (Number) 1L : (Number) 1.0;

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: