我正在用 Java 编写一个模拟重力的程序,其中我有一堆日志语句(到 System.out)。我的程序运行得很慢,我认为日志记录可能是部分原因。有什么方法可以禁用 System.out,这样我的程序在打印时不会变慢,还是我必须手动检查/取消注释每个以启用/禁用调试语句?
10 回答
输出流 gobbler 再次可以工作,可能类似于...
System.setOut(new PrintStream(new OutputStream() {
@Override
public void write(int arg0) throws IOException {
}
}));
但是更好的解决方案是使用已经提到的正式的日志记录实用程序。
我同意其他人的观点,即应该使用适当的记录器。然而,这并非在所有情况下都是可能的。以下代码禁用并且按照OP的要求快速:
System.setOut(new java.io.PrintStream(new java.io.OutputStream() {
@Override public void write(int b) {}
}) {
@Override public void flush() {}
@Override public void close() {}
@Override public void write(int b) {}
@Override public void write(byte[] b) {}
@Override public void write(byte[] buf, int off, int len) {}
@Override public void print(boolean b) {}
@Override public void print(char c) {}
@Override public void print(int i) {}
@Override public void print(long l) {}
@Override public void print(float f) {}
@Override public void print(double d) {}
@Override public void print(char[] s) {}
@Override public void print(String s) {}
@Override public void print(Object obj) {}
@Override public void println() {}
@Override public void println(boolean x) {}
@Override public void println(char x) {}
@Override public void println(int x) {}
@Override public void println(long x) {}
@Override public void println(float x) {}
@Override public void println(double x) {}
@Override public void println(char[] x) {}
@Override public void println(String x) {}
@Override public void println(Object x) {}
@Override public java.io.PrintStream printf(String format, Object... args) { return this; }
@Override public java.io.PrintStream printf(java.util.Locale l, String format, Object... args) { return this; }
@Override public java.io.PrintStream format(String format, Object... args) { return this; }
@Override public java.io.PrintStream format(java.util.Locale l, String format, Object... args) { return this; }
@Override public java.io.PrintStream append(CharSequence csq) { return this; }
@Override public java.io.PrintStream append(CharSequence csq, int start, int end) { return this; }
@Override public java.io.PrintStream append(char c) { return this; }
});
我的样本测量结果是:
- 82ms 完全输出
- 仅覆盖时
write(int)
为57 毫秒OutputStream
- 覆盖
PrintStream
方法时也是31 毫秒 - 注释掉所有
println
和printf
用法时为 5 毫秒
因此,它比这里的其他答案更快,但不能击败不存在的代码(注释掉System.out
s 或换行if (DEBUG)
),因为 varargs 分配数组和框原语或StringBuilder
(+
也)仍然执行。
绝对开始使用日志 API 而不是System.out
. 我强烈推荐Logback。您可以轻松设置仅记录到控制台但可以随时关闭的内容。Logback 配置起来非常简单,但如果您不喜欢配置文件,您甚至可以通过编程方式进行设置。
Log4j也不错,它是与 Logback 同一作者的较早框架,被许多人认为是标准。 SLF4J再次由同一作者撰写,它不是真正的日志框架,而是抽象实际日志实现的标准包装器。Log4j 可以封装在 SLF4J 中,Logback 有原生的 SLF4J 接口。如果我是你,出于各种原因,我会避免使用 Apache Commons Logging 。我从来都不是内置 Java 日志记录 ( java.util.logging
) 的忠实粉丝。
我建议您将来研究 log4j(或类似的库)。它的工作方式与 system.out 相同,但实际上有开关可以在需要时将其关闭。
如果您的应用程序是在命令行启动的,您可以在操作系统级别禁用整个程序的标准输出流。这将有效地禁用所有 System.out.prinln(),而无需您更改任何代码。
在 Linux/Unix 上,您可以通过将 stdout 重定向到 /dev/null 来关闭它:java MyJavaProgram > /dev/null
如果您不介意只浏览一次,您可以创建一个“启用”或“禁用”的常量,并添加一个标志以仅在启用该常量时打印。然后你可以很容易地翻转常数。
public static boolean PRINTLN_ENABLED = true;
if(Constant.PRINTLN_ENABLED)
System.out.println();
由于您在其中一条评论中提到了 Eclipse,您可以在此处找到相关答案:https ://stackoverflow.com/a/799277/1017130
(我最初想将此作为对 shj 答案的评论发布,但似乎我首先需要更多代表)
最好的长期解决方案是使用日志框架。我通常使用内置的日志记录,因为我尽量避免额外的依赖。您可以在此处阅读更多信息:http: //docs.oracle.com/javase/1.4.2/docs/guide/util/logging/overview.html
我怀疑您可以使用System.setOut(PrintStream)
委派给一个PrintStream
不做任何事情的人,但这可能不会消除您的所有开销——例如,我怀疑错误消息的格式仍然会花费您。
我已将此代码放在我的 Web 项目的查找侦听器中一次并解决了问题
/*
* In this case, if you are not in debug mode or any other
*the default system out is replaced internally with this
*implementation, else it works as expected. This way you do not
*have to find and replace anything in your code.
*/
//or as i did servletContext.getInitParameter("mode")
//from web.xml for global parameter
if(!DEBUG) {
System.setOut(
new PrintStream(new OutputStream() {
public void close() {}
public void flush() {}
public void write(byte[] b) {}
public void write(byte[] b, int off, int len) {}
public void write(int b) {}
} );
}
}