Почему в этом случае возвращает null для примитивной работы?
Этот уродливый кусок кода компилируется, но выдает NPE, если s == null
public static boolean isNullOrEmpty(String s)
{
return s != null ? s.isEmpty() : null;
}
пока это не так (как ожидалось):
public static boolean isNullOrEmpty(String s)
{
if(s != null)
return s.isEmpty();
else
return null;
}
Я знаю, что оба они явно ошибаются, но поскольку я нашел первый фрагмент кода в наших источниках, я был очень удивлен, что он скомпилировался.
Изменить:
Здесь соответствующая часть JLS из Java 7. Я догадался, что будет применяться первый оператор, но полужирный.
15.25 Условный оператор?:
[...]
Тип условного выражения определяется следующим образом:
[...]
- Если один из второго и третьего операндов имеет примитивный тип T, а тип другого - результат применения преобразования бокса (п. 5.1.7) в T, то тип условного выражения T.
[...]
- В противном случае второй и третий операнды имеют типы S1 и S2 соответственно. Позволять
T1 - тип, который возникает в результате применения преобразования бокса в S1, и пусть T2
тип, который возникает в результате применения преобразования бокса в S2.
Тип условного выражения является результатом применения захвата
преобразование (§5.1.10) в lub (T1, T2) (§15.12.2.7).
Ответы
Ответ 1
Первый имеет оператор trenary, который имеет тип результата Boolean
. NPE преобразует a null
в Boolean
.
На самом деле это что-то вроде:
Boolean temp = s != null ? s.isEmpty() : null; //no problems here
return temp; //crash when temp==null
Вторая пытается вернуть неправильный тип (объект вместо примитива) - и, следовательно, не компилируется.
Ответ 2
Аналогично Tricky Ternary Operator в JAVA
Тернарный оператор выполняет автобоксинг с использованием правил, указанных в JLS:
Конверсия бокса
Это правило необходимо, так как условный оператор (§15.25) применяет преобразование бокса к типам его операндов и использует приводят к дальнейшим расчетам.
Проблема заключается в использовании Autoboxing в Java. Проблема заключается в том, что второй операнд не является тихим.
public static boolean isNullOrEmpty(String s)
{
return s != null ? null : null;
}
Этот код не будет компилировать
JLS для условного оператора
Ответ 3
Тернарный оператор должен найти наиболее подходящий тип возврата для обоих операндов.
Таким образом, он допускает некоторый "польский" тип возврата.
Как показано в первом фрагменте кода:
public static boolean isNullOrEmpty(String s)
{
return s != null ? s.isEmpty() : null;
}
s.empty()
возвращает примитив boolean
, тогда как третий операнд возвращает null
.
Таким образом, наиболее типичный общий тип возврата boolean
. Задача компилятора похожа на замену строки на:
return s != null ? s.isEmpty() : (Boolean)null;
Метод возвращаемого типа ожидает примитив boolean
, поэтому компилятор говорит: "Классно, мне просто нужно удалить мой результат!". К сожалению, null
не является незаменимым и приводит к уродливому NPE.
С вашим вторым фрагментом:
public static boolean isNullOrEmpty(String s)
{
if(s != null)
return s.isEmpty();
else
return null;
}
Никакого дополнительного "полирования" типа pre-return не производится, поскольку компилятор не связывает оба оператора return в этом коде = > может быть слишком трудным для него.
Итак, в этом случае логично, что код даже не компилируется, поскольку null
НЕ связан с boolean
! Таким образом, никакого приведения не происходит.
Чтобы скомпилировать его, он должен быть записан как:
public static boolean isNullOrEmpty(String s)
{
if(s != null)
return s.isEmpty();
else
return (Boolean)null;
}
Но не мешает известному NPE при попытке распаковать;)