Заявление о недостижимости: пока правда против, если правда

Как мне понять такое поведение компилятора Java?

while (true) return;
System.out.println("I love Java");
// Err: unreachable statement

if (true) return;
System.out.println("I hate Java");
// OK.

Спасибо.

ИЗМЕНИТЬ:

Я узнаю суть через несколько минут:

В первом случае компилятор выдает ошибку из-за бесконечного цикла. В обоих случаях компилятор не думает о коде внутри консеквента.

РЕДАКТИРОВАНИЕ II:

Что меня впечатляет в javac сейчас:

    if (true) return; // Correct
}
    while (true) return; // Correct
}

Похоже, что javac знает, что находится внутри как цикла, так и последовательностей, но когда вы пишете другую команду (как в первом примере), вы получаете неэквивалентное поведение (которое выглядит так, как будто javac забыл, что находится внутри цикла/если).

public static final EDIT III: В результате этого ответа я могу заметить (надеюсь, правильно): выражения как if (arg) { ...; return;} и while (arg) { ...; return;} эквивалентны как семантически, так и синтаксически (в байт-коде) для Java, если argv непостоянна (или фактически окончательный тип) выражение. Если argv является постоянным выражением, байт-код (и поведение) может отличаться.

Отказ от ответственности Этот вопрос касается не недостижимых операторов, а другой обработки логически эквивалентных выражений, таких как while true return и if true return.


person marek094    schedule 11.02.2017    source источник
comment
Дело в том, что если я пишу сумасшедший код, компилятор тоже может вести себя как сумасшедший.   -  person Kayaman    schedule 11.02.2017
comment
@Andremoniy Нет. Пожалуйста, прочитайте внимательно.   -  person marek094    schedule 11.02.2017
comment
@marek094 marek094, каковы ваши намерения для такого сравнения? Java не является языком более низкого уровня, и, так сказать, компилятор не является компилятором машинного языка. Каков точный ответ, который вы ищете, или точный вопрос, который вы собираетесь задать? Кроме того, учитывая количество виртуальных машин и компиляторов, доступных сегодня, это, так сказать, очень общий и менее информативный вопрос, на мой взгляд.   -  person Siddharth Tyagi    schedule 11.02.2017
comment
@SiddharthTyagi Это подготовка к экзамену, на котором я должен ответить на аналогичные вопросы, написанные на бумаге. ¯_(ツ)_/¯   -  person marek094    schedule 11.02.2017
comment
@marek094 звучит как OCJP или OCJD. Попробуйте выучить правила из jls, вам нужно только 60% пройти (я думаю). После экзамена он вам больше не понадобится.   -  person k5_    schedule 11.02.2017
comment
Проблема с вашим вопросом и причина, по которой @Kayaman верен, выделены в вашем отказе от ответственности. Эти два утверждения не логически эквивалентны. Один условный, а другой цикл. Они используют одни и те же ключевые слова в своих проверках, но у них нет и близкой функциональности, намерений или разветвлений.   -  person krillgar    schedule 11.02.2017
comment
@krillgar Есть две части логики - семантическая и синтаксическая. Эти два выражения семантически эквивалентны. Синтаксически - результирующее равенство байтового кода зависит от не-/постоянного выражения в аргументе (как вы можете видеть в ответе k5_).   -  person marek094    schedule 11.02.2017
comment
@ marek094 marek094 у вас есть разумная семантика, только если синтаксис правильный. Никакой компилируемый код не может иметь намерение семантики, но не фактическую семантику.   -  person k5_    schedule 11.02.2017


Ответы (3)


Существуют довольно строгие правила, когда операторы достижимы в java. Эти правила разработаны так, чтобы их можно было легко оценить, и они не должны быть точными на 100%. Это должно предотвратить основные ошибки программирования. Чтобы рассуждать о достижимости в java, вы ограничены этими правилами, «общая логика» не применяется.

Итак, вот правила из Спецификации языка Java 14.21. Заявления о недостижимости

Оператор if-then может завершиться нормально, если он достижим.

Таким образом, без else операторы после if-then всегда достижимы.

Оператор while может завершиться нормально, если верно хотя бы одно из следующего:

  • Оператор while достижим, а выражение условия не является константным выражением (§15.28) со значением true.

  • Существует достижимый оператор break, который выходит из оператора while.

Условие представляет собой константное выражение «истина», разрыва нет. Следовательно, он не завершается нормально.

person k5_    schedule 11.02.2017
comment
Я помню, что видел обоснование для этого. Основная идея заключается в том, что вы можете иметь if(COMPILATION_SWITCH) return; A и иметь правильную компиляцию программы независимо от значения переключателя. - person zch; 11.02.2017

Согласно документам :

За исключением специальной обработки операций while, do и операторов, выражение условия которых имеет постоянное значение true, значения выражений не учитываются при анализе потока.

person squiroid    schedule 11.02.2017

Если вы немного измените свой код (удалите постоянное выражение), чтобы он не вызывал достижимость javac, он фактически будет создавать идентичный байт-код для обоих.

static boolean flag = true;

static void twhile(){
    while (flag) return;
    System.out.println("Java");
}
static void tif(){
    if (flag) return;
    System.out.println("Java");
}

Полученный байт-код:

  static void twhile();
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
      StackMap locals:
      StackMap stack:
     0: getstatic     #10                 // Field flag:Z
     3: ifeq          7
     6: return
      StackMap locals:
      StackMap stack:
     7: getstatic     #20                 // Field java/lang/System.out:Ljava/io/PrintStream;
    10: ldc           #26                 // String Java
    12: invokevirtual #28                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    15: return
      LineNumberTable:
    line 8: 0
    line 9: 7
    line 10: 15
      LocalVariableTable:
    Start  Length  Slot  Name   Signature
      StackMapTable: number_of_entries = 1
    frame_type = 7 /* same */

  static void tif();
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
      StackMap locals:
      StackMap stack:
     0: getstatic     #10                 // Field flag:Z
     3: ifeq          7
     6: return
      StackMap locals:
      StackMap stack:
     7: getstatic     #20                 // Field java/lang/System.out:Ljava/io/PrintStream;
    10: ldc           #26                 // String Java
    12: invokevirtual #28                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    15: return
      LineNumberTable:
    line 12: 0
    line 13: 7
    line 14: 15
      LocalVariableTable:
    Start  Length  Slot  Name   Signature
      StackMapTable: number_of_entries = 1
    frame_type = 7 /* same */
person k5_    schedule 11.02.2017
comment
Да, я читал байт-код для случая с постоянным выражением, и его отличия довольно неясны. - person marek094; 11.02.2017
comment
@ marek094 marek094, поскольку вы не предоставили компилируемый пример для случая постоянного выражения, его трудно сравнивать. В моих тестах он создает noops с разным пухом вокруг него. - person k5_; 11.02.2017
comment
Вы правы, я имел в виду второй пример из моего вопроса. Я знаю, что это не та же самая ситуация, но тоже интересная. - person marek094; 11.02.2017