我很难找到有关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
会可靠地识别和删除这些结构。是否有这些构造的全面列表?
assylias似乎已经找到了答案(让我把它们放在一起):
第14.21。JLS的"Unreachable Statements"规定,通常情况下,代码中任何不可访问的语句都被视为编译时错误,唯一的例外是对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
-雄蕊的"不可访问"部分。javac
似乎可以可靠地做到这一点,但其他编译器可能无法做到。唯一可以确定的方法是通过反编译检查输出,例如Jon Skeet建议使用javap -c
我运行了一些测试,javac似乎(从逻辑上)删除了代码iif(如果且仅当)条件是一个计算结果为false的常量表达式。
总之,常量表达式是仅使用常量作为操作数的表达式,即基元、字符串文字和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/