Я экспериментировал с 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
компилятор, это бросает a NullPointerException
как ожидалось.
Так в компиляторе Java Eclipse существует ли ошибка?
Это ошибка. Вот указанное поведение оператора switch
в соответствии со спецификацией языка Java , 3-е издание :
switch
Оператор SwitchStatement: переключатель (Выражение) SwitchBlock
Когда выполняется оператор
switch
, сначала оцениваетсяВыражение
. Если выражениеоценивается как
null
, возникает исключениеNullPointerException
, и по этой причине весь операторswitch
завершается внезапно.
По-видимому, ошибка в Eclipse не имеет ничего общего с регистром по умолчанию
или перечислением
вообще.
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. Каждый отдельный переключатель
генерирует исключение 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 полностью избавляется от всех конструкций переключателя
. К сожалению, эта оптимизация нарушает спецификацию языка.
Ошибка подана и назначена для исправления.
Olivier Thomann 28-05-2010, 08:37:21 EDT
Мы слишком агрессивны в оптимизации.
Для:
переключатель ((Целое число) ноль) {};
мы оптимизируем весь оператор
switch
, когда мы должны хотя бы оценить выражение.Я посмотрю.
Кандидат в 3.6.1.
Определенно. Если мы посмотрим на главу 14.11 спецификации языка java, то в ней четко указано (в «обсуждении»):
Запрет на использование null в качестве метка переключателя предотвращает писать код, который никогда не может быть выполнен. Если выражение переключателя ссылочного типа, например в штучной упаковке примитивный тип или перечисление, время выполнения ошибка произойдет, если выражение оценивается как null во время выполнения.
Ага. Согласно JLS это ошибка:
Если выражение switch имеет ссылочный тип, такой как коробочный примитивный тип или перечисление, произойдет ошибка времени выполнения, если выражение во время выполнения оценивается в null.