Eclipse ошибка? Переключение на ноль только с регистром по умолчанию

Я экспериментировал с enumи я обнаружил, что следующие компоненты компилируются и нормально работают на Eclipse (идентификатор сборки: 20090920-1017, точная версия компилятора точно не определена):

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

При компиляции и запуске с Eclipse, это печатает "Hello world!" и выходит нормально.

С javac компилятор, это бросает NullPointerException как и ожидалось.

Так есть ли ошибка в компиляторе Eclipse Java?

3 ответа

Решение

Это ошибка. Вот указанное поведение для switch заявление в соответствии со спецификацией языка Java, 3-е издание:

JLS 14.11 switch утверждение

SwitchStatement:
    switch ( Expression ) SwitchBlock

Когда switch оператор выполняется, сначала Expression оценивается. Если Expression оценивает null, NullPointerException брошен и весь switch заявление завершается внезапно по этой причине.

Видимо ошибка в Eclipse не имеет ничего общего с default случай или enum совсем.

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

Приведенный выше код компилируется и работает "отлично" на (по крайней мере, в некоторых версиях) Eclipse. Каждый человек switch бросает NullPointerException при компиляции с javac, что именно так, как указано в спецификации.


Причина

Вот javap -c SwitchingOnAnull когда скомпилировано под 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

}

Кажется, что компилятор Eclipse избавляется от всего switch конструирует целиком К сожалению, эта оптимизация нарушает спецификацию языка.


Официальные слова

Ошибка была подана и назначена для исправления.

Оливье Томанн 2010-05-28 08:37:21 ПО ВОСТОЧНОМУ ВРЕМЕНИ

Мы слишком агрессивны в оптимизации.

За:

  switch((Integer) null) {};

мы оптимизируем весь switch заявление, когда мы должны хотя бы оценить выражение.

Я взгляну.

Кандидат на 3.6.1.

Смотрите также

Определенно. Если мы посмотрим на главу 14.11 спецификации языка Java, она четко говорит (в разделе "обсуждение"):

Запрет на использование null в качестве метки переключателя не позволяет писать код, который никогда не будет выполнен. Если выражение switch относится к ссылочному типу, такому как тип примитива в штучной упаковке или enum, во время выполнения произойдет ошибка, если выражение оценивается как ноль во время выполнения.

Ага. Согласно JLS это ошибка:

Если выражение switch относится к ссылочному типу, такому как тип примитива в штучной упаковке или enum, во время выполнения произойдет ошибка, если выражение оценивается как ноль во время выполнения.

Другие вопросы по тегам