Нечетное троичное поведение Java при назначении значения. Что делает Java за кулисами, чтобы это произошло?

10

Несколько дней назад я столкнулся с увлекательным сценарием, в котором я не смог найти никакой документации о том, как или почему Java допускает следующее. (Этот фрагмент - просто упрощенная форма ошибки.)

    @Test
    public void test() {
      boolean bool = false;
      Integer intVal = Integer.valueOf(5);
      Long longVal = null;
      Long result = bool ? intVal : longVal;

      System.out.println(" > " + result);
   }

во фрагменте выше:

если bool = true, тогда вы получите значение '5';

но если bool = false, то при попытке оценить троичную операцию вы получите исключение нулевого указателя. НЕ заявление печати.


Чтобы это исправить, я просто изменяю «результат» на

Long result = bool ? Long.valueOf(intVal) : longVal;

Это даст ожидаемое поведение, которое мне нужно:

если bool = true, тогда вы получите значение '5';

но если bool = false, тогда вы получите 'null'


теперь самое интересное в том, что если вы разделите это на обычный оператор if / else, то java НЕ позволит вам скомпилировать

longVal = intVal; 

но это не ловит это через троичный оператор. Так что же делает Java, чтобы сделать ее нулевой точкой в ​​исходном фрагменте?

(Ява 11)

Тим З.
источник

Ответы:

10

Когда вы делаете это:

Long result = bool ? intVal : longVal

Это выражение возвращает a longи, когда оно boolравно false, оно пытается распаковать nullзначение Long, чтобы соответствовать resultпеременной, и выдает NPE.

Когда вы делаете это:

Long result = bool ? Long.valueOf(intVal) : longVal

Это выражение уже возвращается, Longтогда нет необходимости в распаковке, и nullзначение успешно присвоено resultпеременной.

Ссылка:

Как обсуждалось в разделе комментариев, чтобы лучше понять, почему это происходит, проверьте следующие разделы JLS:

Диего Магдалено
источник
Я удивлен, что у вас другая справочная таблица 15.25 от A до E, где «ясно», что Integer / Long приводят к bnp (Integer, Long).
Мэтт
Хороший ответ. Обычно, когда я абсолютно не знаю, что происходит внутри, я рекомендую взглянуть на скомпилированный байт-код, который почти точно показывает, что описано. По крайней мере, при извлечении минимального фрагмента кода это более или менее вопрос обучения тому, как его читать и понимать.
Январь состоялся
Как указано в разделе 5.6.2 JLS, «если какой-либо операнд имеет ссылочный тип, он подвергается распаковке без преобразования»; затем применяется «Расширяющееся примитивное преобразование (§5.1.2) [..]»
Диего Магдалено