10

我们有一个巨大的(旧的遗留 Java)代码库,其中许多文件(大约 5k)都有 System.out.println。出于清理/性能原因,我们计划删除它们。我们如何编写一个脚本来替换它们而不在代码中引入任何问题?该脚本不能盲目地删除它们,因为以下情况可能是一个问题:

if ()
  some.code...
else
  System.out.println(...);
DB.close();

我正在考虑用';'替换它们。这将处理上述情况。你看到其他问题了吗?还有其他建议吗?

4

8 回答 8

26

您是否考虑过这种愚蠢的情况:

System.out.println(" Print " +  object.changeState() );

我不认为它会发生,但是 println 执行的方法很可能实际上正在执行系统所依赖的某些操作,并且可能会引入细微的错误(信不信由你,但我已经目睹了这一点)

可能替换为记录器并禁用记录器可能会这样做。

或者使用 NullObject 模式创建一个空对象:

public final class DevNull { 
    public final static PrintStream out = 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) {}

    } );
}

并更换

 System.out.println();

 DevNull.out.println();
于 2009-02-21T03:58:18.900 回答
12

Log4E 是一个具有“替换 System.out.println()”功能的 Eclipse 插件。它会愉快地将所有那些讨厌的 println 调用转换为 log4j 调用。它甚至会用日志级别检查来包装它们。

于 2009-02-21T04:12:35.980 回答
8

扩展 Oscar 的概念,您可以做得更好恕我直言:

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) {}

        } );
    }
}

在这种情况下,如果您未处于调试模式或任何其他模式,默认系统输出将在内部替换为 devNull 实现,否则它会按预期工作。这样您就不必在代码中查找和替换任何内容。

于 2009-02-21T10:09:17.603 回答
6

您可以通过调用 Systems.setOut 并传入您自己的 OutputStream 开始,它什么都不做。这将帮助您查看是否有性能提升。这比删除它们更安全(因为 Oscar 指出的原因 - 副作用编码)。如果性能提升可以忽略不计,那么您可能希望将精力集中在其他地方。

我的上述方法有两个问题:

  1. 您想保留的任何 System.out.printlns 也会消失
  2. 字符串连接仍然会发生(这可能会很昂贵,具体取决于有多少)

然而,这是一个很好的快速测试,看看您是否获得了您正在寻找的性能提升。

于 2009-02-21T04:14:22.713 回答
4

您可以使用条件编译来进行带有打印语句的调试构建和没有它们的发布构建。

基本上,这个想法是创建一个具有最终静态布尔值的最终静态类,您可以在编译时将其用作开关。

public final class Debug {
   //set to false to allow compiler to identify and eliminate
   //unreachable code
   public static final boolean ON = true;
}

然后您可以将所有System.out.println语句替换为

if(Debug.ON)
{
    System.out.println...
}

由于编译器将忽略任何无法访问的代码分支,因此您可以ON = false在进行发布构建时进行设置,打印语句将从您的字节码中排除。

注意:这不涉及Oscar指出的情况,即 print 语句可能会更改某些对象的状态。正如他所建议的,您可以在发布模式下使用条件编译打印到空对象,而不是完全删除打印件。

于 2009-02-21T04:09:47.110 回答
1

我个人会{}改用,但我认为它的工作原理是一样的。

于 2009-02-21T03:45:40.020 回答
0

我在 perl 中编写了一个正则表达式,将字符串“System.out.println”替换为“;//System.out.println”。我相信很少有这种情况会破坏构建。它只会变成一个“else ;”,它被编译成零字节码指令。

看起来这就是你所提议的。它对我有用——除非你在同一行有其他语句。然而,这是一种糟糕的风格(我知道我没有那样做)。

于 2009-02-21T08:41:26.097 回答
0

您是否考虑过编辑这些源文件以删除这些行?

您可能会发现开发人员只需几天时间就可以摆脱其中的大部分。我们遇到了类似的问题,我刚刚起得很早,检查了我们所有的文件以清除垃圾。

我使用 Eclipse 和清理保存功能同时清理导入和内容。

这是一件非常有治疗作用的事情!

于 2009-02-21T13:37:53.890 回答