【问题标题】:How to remove System.out.println's from codebase如何从代码库中删除 System.out.println
【发布时间】:2010-10-08 23:58:11
【问题描述】:

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

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

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

【问题讨论】:

  • pontificate mode on :-) 这就是(在许多其他原因中)为什么我总是使用 { } 即使是一行的事情! (我知道这是遗产,可能不是你做的)。我会用 { } 而不是 ;但两者都很好。
  • 教皇回应:我正要评论完全相同的事情。
  • 我知道,而且代码中可能没有。但是,由于有很多文件和遗留问题(这几乎总是意味着不好),我不想冒险。

标签: java performance scripting code-cleanup


【解决方案1】:

你有没有考虑过这种愚蠢的情况:

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();

【讨论】:

  • 我很喜欢,奥斯卡。好想,我必须说。
  • 太棒了,我不得不破解 NetBeans 并尝试一下。
  • 好主意 - 如果您将“愚蠢的情况”从 object.stateChanged() 更改为 object.changeState() 会更容易,否则这听起来像是对我的对象的查询始终认为没有业务更改对象状态。 ...个人习惯...
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    扩展 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 实现,否则它会按预期工作。这样您就不必在代码中查找和替换任何内容。

    【讨论】:

    • 够有趣的。可以使用记录器处理新的打印语句,并以此完全禁用 System.out。 :)
    • 那么,我们可以称之为“奥斯卡雷耶斯+蜥蜴比尔”的方法吗? :P :P +1
    • 这是假设没有其他代码已经在执行 setOut ;) 开个玩笑。这是一个很好的建议。
    • 这可能是最简单、最快的方法。如果不需要合法的控制台输出,绝对是可行的方法。
    【解决方案4】:

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

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

    1. 您想保留的任何 System.out.printlns 也会消失
    2. 字符串连接仍会发生(根据数量不同,这可能会很昂贵)

    但是,这是一个很好的快速测试,可以查看您是否获得了所需的性能提升。

    【讨论】:

      【解决方案5】:

      您可以使用conditional compilation 进行带有打印语句的调试构建和不使用它们的发布构建。

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

      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 指出的情况,即打印语句可能会更改某些对象的状态。正如他所建议的,您可以在发布模式下使用条件编译打印到空对象,而不是完全删除打印。

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

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

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

          【讨论】:

            【解决方案8】:

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

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

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

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

            【讨论】:

              猜你喜欢
              • 2014-10-06
              • 2013-09-11
              • 1970-01-01
              • 2011-09-21
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-09-11
              相关资源
              最近更新 更多