Eclipse bug? Switching on a null with only default case
Asked Answered
C

3

31

I was experimenting with enum, and I found that the following compiles and runs fine on Eclipse (Build id: 20090920-1017, not sure exact compiler version):

public class SwitchingOnAnull {
    enum X { ,; }
    public static void main(String[] args) {
        X x = null;
        switch(x) {
            default: System.out.println("Hello world!");
        }
    }
}

When compiled and run with Eclipse, this prints "Hello world!" and exits normally.

With the javac compiler, this throws a NullPointerException as expected.

So is there a bug in Eclipse Java compiler?

Congener answered 28/5, 2010 at 5:42 Comment(5)
Have you raised a bug over at eclipse.org?Thundering
Or post in the eclipse forum.Mortify
@Rulmeq, @fastcodejava: see my answer. Bug accepted, assigned, candidate for 3.6.1.Congener
@poly - no offense meant. Good that you posted here as well.Mortify
See also riedquat.de/blog/2011-03-04-02Tati
C
27

This is a bug. Here's the specified behavior for a switch statement according to the Java Language Specification, 3rd Edition:

JLS 14.11 The switch Statement

SwitchStatement:
    switch ( Expression ) SwitchBlock

When the switch statement is executed, first the Expression is evaluated. If the Expression evaluates to null, a NullPointerException is thrown and the entire switch statement completes abruptly for that reason.

Apparently the bug in Eclipse has nothing to do with default case or enum at all.

public class SwitchingOnAnull {
    public static void main(String[] args) {        
        java.math.RoundingMode x = null;
        switch(x) {};

        switch((Integer) null) {};

        switch((Character) null) {
            default: System.out.println("I've got sunshine!");
        }       
    }
}

The above code compiles and runs "fine" on (at least some version of) Eclipse. Each individual switch throws a NullPointerException when compiled with javac, which is exactly as the specification mandates.


The cause

Here's javap -c SwitchingOnAnull when compiled under Eclipse:

Compiled from "SwitchingOnAnull.java"
public class SwitchingOnAnull extends java.lang.Object{
public SwitchingOnAnull();
Code:
 0: aload_0
 1: invokespecial  #8; //Method java/lang/Object."<init>":()V
 4: return

public static void main(java.lang.String[]);
Code:
 0: aconst_null
 1: astore_1
 2: getstatic     #16; //Field java/lang/System.out:Ljava/io/PrintStream;
 5: ldc           #22; //String I've got sunshine!
 7: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
10: return

}

It seems that the Eclipse compiler gets rid of the entire switch constructs entirely. Unfortunately this optimization breaks the language specification.


The official words

The bug has been filed and assigned for fix.

Olivier Thomann 2010-05-28 08:37:21 EDT

We are too aggressive on the optimization.

For:

  switch((Integer) null) {};

we optimize out the whole switch statement when we should at least evaluate the expression.

I'll take a look.

Candidate for 3.6.1.

See also

Congener answered 28/5, 2010 at 5:54 Comment(5)
weird. how would Eclipse cause this bug? Doesn't Eclipse use java and javac behind the scenes? very interesting.Dedal
That's funny. Some EDT developer was a bit too smart when implementing an optimization it seems.Inge
It doesn't seem to be registered as a bug: bugs.eclipse.org/bugs/… . So you could create a ticket there.Bezanson
@darren no. Eclipse has its own compiler, entirely separate from javac. Do a stackoverflow search for "eclipse javac" and you'll see there are a number of cases (especially related to generics) where they behave differently.Empiric
@Inge - You're correct, they're too smart. They implemented it in such a way that makes sense when the language definition doesn't. Throwing an exception rather than going to default is definitely retarded. Now I have to wrap a try/catch for a NullPointerException where the catch will do the exact same thing the default does. Edit: Actually, I'll insert a null check, it's quicker than waiting to catch the exception, particularly since it's expected.Foreclosure
S
4

Definitly. If we look at the chapter 14.11 of the java language specification, it clearly states (under 'discussion'):

The prohibition against using null as a switch label prevents one from writing code that can never be executed. If the switch expression is of a reference type, such as a boxed primitive type or an enum, a run-time error will occur if the expression evaluates to null at run-time.

Subclass answered 28/5, 2010 at 5:55 Comment(1)
I can imagine a better rule: 1. allow a null switch label not covered by default, 2. issue a warning/error whenever the null label is missing and the expression is not a primitive. 3. enjoy shorter code and zero risk of NPE in switch.Taam
I
1

Yep. According to the JLS it's a bug:

If the switch expression is of a reference type, such as a boxed primitive type or an enum, a run-time error will occur if the expression evaluates to null at run-time.

Inge answered 28/5, 2010 at 5:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.