Недостижимая ошибка в коде против мертвого кодекса, предупреждающего на Яве под Затмением?

Делает любой знает почему:

public void foo()
{
    System.out.println("Hello");
    return;
    System.out.println("World!");
}

Был бы сообщен как «недостижимая ошибка» под Затмением, но

public void foo()
{
    System.out.println("Hello");
    if(true) return;
    System.out.println("World!");
}

Только вызывает «Мертвый кодекс» предупреждение?

Единственное объяснение, о котором я могу думать, состоит в том, что Явский компилятор только сигнализирует первое, и что некоторый дополнительный анализ в Затмении выясняет второе. Однако, если это так, почему Явский компилятор не может выяснить этот случай во время компиляции?

Разве Явский компилятор не выяснил бы во время компиляции, что, если (верный) не имеет никакого эффекта, таким образом уступая bytecode, который чрезвычайно идентичен? В каком пункте применен достижимый кодовый анализ?

Я предполагаю, что более общий способ думать об этом вопросе: «когда достижимый кодовый анализ применен»? В преобразовании второго Явского кодового фрагмента к финалу bytecode, я уверен, что в какой-то момент, «если (истинный)» эквивалент во время выполнения удален, и представления этих двух программ, становятся идентичными. Явский компилятор тогда не применил бы свой достижимый кодовый анализ снова?

53
задан Uri 26 January 2010 в 07:10
поделиться

6 ответов

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

Поскольку зачем Eclipse обнаруживает Dead Code, ну, это просто удобство интегрированного инструмента разработки со встроенным компилятором, который может быть более широким, что может быть в отличие от JDK, чтобы обнаружить этот тип кода.

Обновление : JDK фактически устраняет мертвый код.

public class Test {
    public void foo() {
        System.out.println("foo");
        if(true)return;
        System.out.println("foo");
    }
    public void bar() {
        System.out.println("bar");
        if(false)return;
        System.out.println("bar");
    }
}

Javap -c говорит:

public class Test extends java.lang.Object{
public Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."":()V
   4:   return

public void foo();
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc             #3; //String foo
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/StrV
   8:   return

public void bar();
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc             #5; //String bar
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   11:  ldc             #5; //String bar
   13:  invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   16:  return

}

Как к тому, почему он (Солнце) не дает предупреждения об этом, я понятия не имею :) По крайней мере, компилятор JDK на самом деле DCE (устранение мертвого кода) Отказ

34
ответ дан 7 November 2019 в 08:47
поделиться

Первый делает Компиляция (у вас есть ошибка), вторые компилирования (вы только что получили предупреждение). Это разница.

Как к тому, почему Eclipse обнаруживает Dead Code, ну, это просто удобство интегрированного инструмента разработки со встроенным компилятором, который может быть более широким, что может быть в отличие от JDK для выявления этого типа кода.

Обновление : JDK фактически устраняет мертвый код.

public class Test {
    public void foo() {
        System.out.println("foo");
        if(true)return;
        System.out.println("foo");
    }
    public void bar() {
        System.out.println("bar");
        if(false)return;
        System.out.println("bar");
    }
}

JAVAP -C говорит:

public class Test extends java.lang.Object{
public Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."":()V
   4:   return

public void foo();
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc             #3; //String foo
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/StrV
   8:   return

public void bar();
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc             #5; //String bar
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   11:  ldc             #5; //String bar
   13:  invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   16:  return

}

Как к тому, почему он (Sun) не дает предупреждения об этом, я понятия не имею :) По крайней мере, компилятор JDK на самом деле DCE (удаление мертвого кода) Отказ

-121--1020436-

, если (true) - это немного более тонкое, чем «недостижимое»; Потому что это затвердело возвращение , всегда сделает следующий код недоступен, но изменяя условие в , если может сделать следующее утверждение доступным.

Наличие условного существа означает, что есть случайное состояние может измениться. Есть случаи, когда в скобках есть что-то более сложное , и для человеческого читателя, и не очевидно для человеческого читателя, и не очевидно, что следующий код «умерзен», но замечает компиляторы, так что это может предупредить вас о Это.

здесь упоминается затмение, и это делает вещи немного более сложными для пользователя; Но на самом деле под EUCLIPSE является просто (очень сложный) Java Compiler, который возникает с большим количеством коммутаторов для предупреждений и т. Д., Что Eclipse может включаться и выключать. Другими словами, вы не получаете довольно широту разных предупреждений / ошибок с прямой javac javac . У вас нет удобных средств, чтобы включить все они. Но это та же дело, просто с большим количеством колоколов и свистков.

2
ответ дан 7 November 2019 в 08:47
поделиться

Я думаю, что один из вариантов - это то, что недоступный код, скорее всего, является ошибкой, и JLS пытается защитить вас от таких ошибок.

Разрешение если (правда) возвратиться; является хорошим способом обойти ограничение JLS, если вы действительно хотите сделать это специально. Если JLS остановит это, то это будет мешать. Кроме того, она также должна остановиться:

 public static boolean DEBUG = true; //In some global class somewhere else


 ...

 if (DEBUG) return; //in a completely unrelated class.

 ...

Потому что DEBUG константа полностью выстроена в линию, и функционально эквивалентна простому набору true в условии if. С точки зрения JLS эти два случая очень похожи.

2
ответ дан 7 November 2019 в 08:47
поделиться

Разница в семантике между временем исполнения и временем компиляции. Во втором примере код компилируется в байткоде в ветку if-else, и затмение достаточно умно, чтобы сказать, что остальная часть никогда не будет достигнута во время выполнения. Затмение только предупреждает вас, потому что это все еще легальный код.

В вашем первом примере это ошибка, потому что код является незаконным по определению java. Компилятор не позволяет создавать байтовый код с недоступными выражениями.

0
ответ дан 7 November 2019 в 08:47
поделиться

Это состоит в том, чтобы допустить своего рода условно с компиляцией .
Это не ошибка с , если , но компилятор будет поменять ошибку для , в то время как , , в то время как и для .
Это нормально:

if (true) return;    // or false
System.out.println("doing something");

Это ошибки

while (true) {
}
System.out.println("unreachable");

while (false) {
    System.out.println("unreachable");
}

do {
} while (true);
System.out.println("unreachable");

for(;;) {
}
System.out.println("unreachable");

это объясняется в конце JLS 14.21: недоступные высказывания :

Обоснование для этого различного обращения состоит в том, чтобы позволить программистам определить «переменные флага». "Как:

  Статический конечный логический отладчик = false;
 

, а затем напишите код, такой как:

 , если (отладки) {x = 3;  }
 

Идея состоит в том, что должно быть возможность изменить значение отладки от FALSE в True или от True к false, а затем правильно компилировать код без других изменений в тексте программы.

14
ответ дан 7 November 2019 в 08:47
поделиться

Недостижимый код - это ошибка согласно Спецификации языка Java .

Цитата из JLS:

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

Это означает, что блок if не принимается во внимание, поскольку если вы пройдете по одному из путей оператора if , вы сможете достичь окончательного оператора печати . Если вы измените свой код на:

public void foo() {
    System.out.println("Hello");
    if (true)
        return;
    else
        return;
    System.out.println("World!");
}

, то он внезапно перестанет компилироваться, поскольку нет пути через оператор if , который позволил бы достичь последней строки.

То есть компилятору, совместимому с Java, не разрешено компилировать ваш первый фрагмент кода. Чтобы процитировать JLS:

В качестве примера следующий оператор приводит к ошибке времени компиляции:

while (false) { x=3; }

потому что оператор x = 3; недоступен; но внешне похожий случай:

if (false) { x=3; }

не приводит к ошибке времени компиляции. Оптимизирующий компилятор может понять, что оператор x = 3; никогда не будет выполняться и может опустить код для этого оператора из сгенерированного файла класса, но оператор x = 3; не считается «недостижимым» в техническом смысле, указанном здесь.

Второе предупреждение Eclipse о мертвом коде - это предупреждение, генерируемое компилятором, которое не является «недостижимым», согласно JLS, но на практике таковым является. Это дополнительная проверка стиля lint , которую предоставляет Eclipse. Это совершенно необязательно, и, используя конфигурацию Eclipse, можно отключить или превратить в ошибку компилятора вместо предупреждения.

Этот второй блок представляет собой «запах кода», блоки if (false) обычно вставляются для отключения кода в целях отладки, оставляя его позади, как правило, случайно и, следовательно, выдается предупреждение.

Фактически, Eclipse выполняет еще более сложные тесты, чтобы определить возможные значения для оператора if, чтобы определить, можно ли выбрать оба пути. Например, Eclipse также будет жаловаться на мертвый код в следующем методе:

public void foo() {
    System.out.println("Hello");
    boolean bool = Random.nextBoolean();
    if (bool)
        return;
    if (bool || Random.nextBoolean())
      System.out.println("World!");
}

Он сгенерирует недостижимый код для второго оператора if, поскольку он может считать, что bool должно быть только false на этом этапе кода. В таком коротком фрагменте кода очевидно, что два оператора if проверяют одно и то же, однако, если в середине есть 10-15 строк кода, это может быть уже не так очевидно.

Итак, вкратце, разница между ними: один запрещен JLS, а другой нет, но обнаруживается Eclipse как услуга для программиста.

25
ответ дан 7 November 2019 в 08:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: