Возможности устранения кода 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/