如何从Java中的生产代码中删除调试语句

Jon*_*han 16 java compiler-construction debugging

编译器是否可以从生产代码中删除用于调试目的的语句(例如日志记录)?调试语句需要以某种方式标记,可能使用注释.

设置属性(debug = true)很容易并在每个调试语句中检查它,但这会降低性能.如果编译器只是简单地使调试语句消失,那将是很好的.

Mar*_*ouf 23

两个建议.

第一: 真正的日志记录,使用记录现代包装像log4j的或Java自身内置的日志记录.不要太担心性能,日志级别检查大约为纳秒级.(这是一个整数比较).

如果你有多个日志语句,请保护整个块:

(log4j,例如:)

if (logger.isDebugEnabled()) {

  // perform expensive operations
  // build string to log

  logger.debug("....");
}
Run Code Online (Sandbox Code Playgroud)

这为您提供了在运行时添加的能力控制记录.必须重新启动并运行调试版本可能非常不方便.

第二:

您可能会发现断言更符合您的需求.断言是一个语句,它使用可选消息求值为布尔结果:

 assert (sky.state != FALLING) : "The sky is falling!";
Run Code Online (Sandbox Code Playgroud)

每当断言导致错误时,断言失败并抛出包含您的消息的AssertionError(这是一个未经检查的异常,旨在退出应用程序).

整洁的是,JVM对它们进行了特殊处理,并且可以使用VM参数(无需重新编译)在运行时切换到类级别.如果未启用,则开销为零.


izb*_*izb 10

public abstract class Config
{
    public static final boolean ENABLELOGGING = true;
}
Run Code Online (Sandbox Code Playgroud)
import static Config.*;

public class MyClass
{
    public myMethod()
    {
        System.out.println("Hello, non-logging world");

        if (ENABLELOGGING)
        {
            log("Hello, logging world.");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器将使用"Hello,logging world"删除代码块.如果ENABLE_LOGGING设置为true,因为它是静态最终值.如果使用诸如proguard之类的混淆器,那么Config类也将消失.

混淆器也会允许这样的事情:

public class MyClass
{
    public myMethod()
    {
        System.out.println("Hello, non-logging world");

        Log.log("Hello, logging world.");
    }
}
Run Code Online (Sandbox Code Playgroud)
import static Config.*;

public abstract class Log
{
    public static void log(String s)
    {
        if (ENABLELOGGING)
        {
            log(s);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Log#log方法在编译器中会减少为零,并且由混淆器删除,以及对该方法的任何调用,最终甚至会删除Log类.