如何从 Java 的生产代码中删除调试语句
2022-09-03 04:42:53
编译器是否可以从生产代码中删除用于调试目的(如日志记录)的语句?调试语句需要以某种方式标记,可能使用注释。
设置属性(debug = true)并在每个调试语句中检查它很容易,但这会降低性能。如果编译器只是使调试语句消失,那就太好了。
编译器是否可以从生产代码中删除用于调试目的(如日志记录)的语句?调试语句需要以某种方式标记,可能使用注释。
设置属性(debug = true)并在每个调试语句中检查它很容易,但这会降低性能。如果编译器只是使调试语句消失,那就太好了。
两个建议。
首先:对于真正的日志记录,请使用现代日志记录包,如log4j或java自己的内置日志记录。不要太担心性能,日志记录级别检查在纳秒左右。(这是一个整数比较)。
如果您有多个日志语句,请保护整个块:
(log4j,例如:)
if (logger.isDebugEnabled()) {
// perform expensive operations
// build string to log
logger.debug("....");
}
这为您提供了在运行时控制日志记录的附加功能。必须重新启动并运行调试版本可能非常不方便。
第二:
你可能会发现断言更符合你的需求。断言是一个语句,其计算结果为布尔结果,并带有可选消息:
assert (sky.state != FALLING) : "The sky is falling!";
每当断言导致 false 时,断言就会失败,并且会引发包含消息的 AssertionError(这是一个未经检查的异常,旨在退出应用程序)。
巧妙的是,JVM对这些内容进行了特殊处理,并且可以在运行时使用VM参数(无需重新编译)切换到类级别。如果未启用,则开销为零。
public abstract class Config
{
public static final boolean ENABLELOGGING = true;
}
import static Config.*;
public class MyClass
{
public myMethod()
{
System.out.println("Hello, non-logging world");
if (ENABLELOGGING)
{
log("Hello, logging world.");
}
}
}
如果ENABLE_LOGGING设置为 true,则编译器将删除其中带有“Hello, logging world.”的代码块,因为它是静态最终值。如果您使用诸如 proguard 之类的混淆器,则 Config 类也将消失。
混淆器也会允许这样的事情:
public class MyClass
{
public myMethod()
{
System.out.println("Hello, non-logging world");
Log.log("Hello, logging world.");
}
}
import static Config.*;
public abstract class Log
{
public static void log(String s)
{
if (ENABLELOGGING)
{
log(s);
}
}
}
方法 Log#log 在编译器中将减少到零,并由混淆器删除,以及对该方法的任何调用,最终甚至 Log 类本身也将被删除。