Возможности устранения кода Javac

Мне трудно найти информацию о javacВозможности устранения кода:

Я читал, что если у вас есть что-то вроде следующего, if-устройство будет исключено:

static final boolean DEBUG = false;

if (DEBUG) System.out.println("Hello World!"); // will be removed

Но как насчет этого, например:

static final int VALUE = 3;

if (VALUE > 9) System.out.println("VALUE > 9 ???"); // will this be removed?

Или это:

static final SomeEnum VALUE = SomeEnum.FOO;

if (VALUE==SomeEnum.BAR) System.out.println("Bar???"); // will this be removed?

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

4 ответа

Решение

Ассилиас, кажется, нашел ответ (позвольте мне собрать все это вместе):

Глава "14.21. Недоступные утверждения" JLS определяет, что, как правило, любое недостижимое утверждение в коде считается ошибкой времени компиляции, с единственным исключением, являющимся специальной обработкой if -выражения, специально предназначенные для условных компиляций.

Поэтому единственная конструкция, которая может привести к исключению кода (если компилятор решит это сделать!), Это:

if (compileTimeConstantExpression) {
    doThis(); // may be removed if compileTimeConstantExpression == false;
} else {
    doThat(); // may be removed if compileTimeConstantExpression == true;
}

(else -часть необязательна, конечно)

Все другие конструкции, которые допускают удаление кода, как, например, while (false) ..., запрещены и вызывают ошибку времени компиляции, а не приводят к условной компиляции.

Определение того, что является приемлемым compileTimeConstantExpression можно найти в главе "15.28. Выражения констант" JLS. Другая отличная страница с дополнительными примерами может быть найдена здесь: константы времени компиляции в Java

Примечание. Компилятору не требуется удалять "недоступные" разделы if -stament. javac кажется, делает это надежно, но другие компиляторы не могут. Единственный способ узнать наверняка - проверить вывод с помощью декомпиляции, например, используя javap -c как предложено Джоном Скитом.

Я провел несколько тестов, и кажется (логически), что javac удаляет код, если условие является константным выражением, которое оценивается как ложное.

Таким образом, константные выражения являются выражениями, которые используют только константы в качестве операндов, т.е. примитивы, строковые литералы и final примитивы или строковые переменные, которые были инициализированы с постоянным значением.

Обратите внимание, что это зависит от компилятора, поскольку JLS не заставляет компилятор быть таким умным, как объяснено в самом низу 14.21:

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

Я вижу, что для второго примера это тоже удаляется

это был мой класс

public class Test {

    public static void main(String[] args) throws Exception{
        final int VALUE = 3;
        if (VALUE > 9) System.out.println("VALUE > 9 ???");
    }
}

и это декомпилированная версия

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

public static void main(java.lang.String[])   throws java.lang.Exception;
  Code:
   0:   return

}

Я думаю, что это зависит от реализации (Oracle, IBM,...).

Если вы интересуетесь версией Oracle, для поиска ресурсов лучше всего подойдет проект OpenJDK: http://openjdk.java.net/groups/compiler/

Другие вопросы по тегам