Подтвердить что ты не робот

Почему в этом случае возвращает 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).
4b9b3361

Ответ 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 при попытке распаковать;)