Eclipse ошибка? Переключение на ноль только с регистром по умолчанию - PullRequest
31 голосов
/ 28 мая 2010

Я экспериментировал с 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 ]

27 голосов
/ 28 мая 2010

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

JLS 14.11 switch Заявление

SwitchStatement:
    switch ( Expression ) SwitchBlock

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

Очевидно, что ошибка в Eclipse не имеет ничего общего с default case или 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. К сожалению, эта оптимизация нарушает спецификацию языка.


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

Ошибка была зарегистрирована и исправлена.

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

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

Для:

  switch((Integer) null) {};

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

Я посмотрю.

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

Смотри также

4 голосов
/ 28 мая 2010

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

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

1 голос
/ 28 мая 2010

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

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

...