2015-08-12 3 views
7

Я нашел странное поведение в текущей версии Java 8. На мой взгляд, следующий код должен быть хорошо, но JVM бросает NullPointerException:NullPointerException вместо нулевой (? JVM Bug)

Supplier<Object> s =() -> false ? false : false ? false : null; 
s.get(); // expected: null, actual: NullPointerException 

Это не имеет значения, какое именно лямбда-выражение оно (то же самое с java.util.function.Function) или какие общие типы используются. Вместо false ? : также могут быть более значимые выражения. Пример выше очень короткий. Вот более красочный пример:

Function<String, Boolean> f = s -> s.equals("0") ? false : s.equals("1") ? true : null; 
f.apply("0"); // false 
f.apply("1"); // true 
f.apply("2"); // expected: null, actual: NullPointerException 

Однако эти куски кода работать нормально:

Supplier<Object> s =() -> null; 
s.get(); // null 

и

Supplier<Object> s =() -> false ? false : null; 
s.get(); // null 

Или с функцией:

Function<String, Boolean> f = s -> { 
    if (s.equals("0")) return false; 
    else if (s.equals("1")) return true; 
    else return null; 
}; 
f.apply("0"); // false 
f.apply("1"); // true 
f.apply("2"); // null 

я тестировал с двумя Версии Java:

~# java -version

OpenJDK версия "1.8.0_66-внутренний" OpenJDK Runtime Environment (сборка 1.8.0_66-b01 внутренний) OpenJDK 64-разрядный сервер ВМ (сборка 25,66-b01, смешанный режим)

C:\>java -version

ява версия "1.8.0_51" Java (TM) SE Runtime Environment (строить 1.8.0_51-b16) Java HotSpot (TM) 64-разрядного сервера VM (сборка 25,51-B03, смешанный режим)

+4

Как это отличается от 'Object a = false? false: false? false: null; 'который также дает« NullPointerException »? –

+0

Это происходит в Java 7 и Java 8 (OpenJDK). –

+1

@ bayou.io Как так? Лямбда ничего не добавляют. «Проблема» - это тернарные выражения. –

ответ

7

Это не имеет ничего общего с лямбда-выражений; просто возвращаемый тип тернарного оператора в этом случае равен boolean, поэтому будет использоваться автоматическая распаковка.

NPE брошено здесь также:

public class Main { 

    private static Object method() { 
     return false ? false : false ? false : null; 
    } 

    public static void main(String[] args) { 
     System.out.println(method()); 
    } 
} 

Итак, что же здесь происходит?

Во-первых, 'встроенного' выражение (false ? false : null) оценивается в соответствии с JLS §15.25:

Условный оператор синтаксически правоассоциативной (она группирует справа-налево). Таким образом, a? B: c? D: e? F: g означает то же, что и a? B: (c? D: (e? F: g)).

Тип встроенного выражения Boolean (в штучной упаковке boolean), так что оба false и null может поместиться в нем.

Тогда все выражение:

false ? false : (Boolean expression) 

Затем, снова в соответствии с JLS §15.25:

Если один из второго и третьего операндов примитивного типа Т и тип другой результат заключается в применении преобразования бокса (§5.1.7) в T, то тип условного выражения T.

Таким образом, первый аргумент примитивного типа boolean (T в спецификации), тип другой является штучной упаковке T (Boolean), так что тип всего выражения boolean.

Затем во врезке встроенное выражение оценивается как null, которое автоматически распаковывается до boolean, вызывая NPE.

+1

ну, код OP находится в java8, поэтому мы должны рассмотреть целевую типизацию 'Object' , и мы должны проанализировать, должно ли оно влиять на операнды; почему распаковка выполняется вместо бокса. – ZhongYu

+0

Тогда почему 'false? false: false? Boolean.FALSE: null; 'все еще бросает NPE. Второй операнд вложенного выражения - 'Boolean', поэтому никакое преобразование бокса не будет применяться (§5.1.7). Внешнее выражение было бы «ложным»? false: (Boolean expression) '. Следующая строка в JLS § 15.25 гласит: «Если один из второго и третьего операндов имеет нулевой тип, а тип другого - ссылочный тип, то тип условного выражения является ссылочным типом.« ОК, но, наконец, что было бы равно false? false: (Boolean) null'. – steffen

+1

'false? false: false? Boolean.FALSE: null - это то же самое. Вложенное тернарное выражение оценивается как 'Boolean', и все выражение возвращает' boolean', потому что это примитивный тип 'T ', указанный выше. –

Смежные вопросы