【问题标题】:Clearing a string buffer/builder after loop循环后清除字符串缓冲区/构建器
【发布时间】:2011-01-15 14:16:50
【问题描述】:

如何在循环后清除 Java 中的字符串缓冲区,以便下一次迭代使用清除字符串缓冲区?

【问题讨论】:

  • 另一个问题:为什么你只在循环的一次迭代中使用 SB?是否还有另一个内部迭代?如果您只是想做 A+B+C+D(Java 编译器将在内部使用 SB),那么 SB 是不值得的。如果您想有条件地添加字符串的一部分,它会有所帮助,否则......只需使用“+”。

标签: java string buffer


【解决方案1】:

我使用下面的代码来存储密码以进行临时处理,如正则表达式匹配,并在完成后将其清除。通常的删除方法不会重置所有字符,这不适合我。这段代码满足了我的要求。

    public static void clear(StringBuilder value) {
        for (int i = 0, len = value.length(); i < len; i++) {
            value.setCharAt(i, Character.MIN_VALUE);
        }
        value.setLength(0);
    }

    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("clear this password");
        // use & process sb
        clear(sb);
    }

【讨论】:

    【解决方案2】:
    public void clear(StringBuilder s) {
        s.setLength(0);
    }
    

    用法:

    StringBuilder v = new StringBuilder();
    clear(v);
    

    为了可读性,我认为这是最好的解决方案。

    【讨论】:

      【解决方案3】:

      那里已经有了很好的答案。只需为 StringBuffer 和 StringBuild 性能差异添加基准结果,在循环中使用新实例或在循环中使用 setLength(0)。

      总结是:在一个大循环中

      • StringBuilder 比 StringBuffer 快很多
      • 在循环中创建新的 StringBuilder 实例没有 与 setLength(0) 的区别。 (setLength(0) 比创建新实例有非常非常非常小的优势。)
      • 通过在循环中创建新实例,StringBuffer 比 StringBuilder 慢
      • StringBuffer 的 setLength(0) 比在循环中创建新实例要慢得多。

      非常简单的基准测试(我只是手动更改了代码并进行了不同的测试):

      public class StringBuilderSpeed {
      public static final char ch[] = new char[]{'a','b','c','d','e','f','g','h','i'};
      
      public static void main(String a[]){
          int loopTime = 99999999;
          long startTime = System.currentTimeMillis();
          StringBuilder sb = new StringBuilder();
          for(int i = 0 ; i < loopTime; i++){
              for(char c : ch){
                  sb.append(c);
              }
              sb.setLength(0);
          }
          long endTime = System.currentTimeMillis();
          System.out.println("Time cost: " + (endTime - startTime));
      }
      

      }

      循环中的新 StringBuilder 实例: 时间成本:3693、3862、3624、3742

      StringBuilder 设置长度: 时间成本:3465、3421、3557、3408

      循环中的新 StringBuffer 实例: 时间成本:8327、8324、8284

      StringBuffer 设置长度 时间成本:22878、23017、22894

      再次使用 StringBuilder setLength 确保我的 labtop 在使用这么长的 StringBuffer setLength 时不会遇到问题 :-) 时间成本:3448

      【讨论】:

        【解决方案4】:

        你有两个选择:

        任意使用:

        sb.setLength(0);  // It will just discard the previous data, which will be garbage collected later.  
        

        或使用:

        sb.delete(0, sb.length());  // A bit slower as it is used to delete sub sequence.  
        

        注意

        避免在循环中声明StringBufferStringBuilder 对象,否则每次迭代都会创建新对象。创建对象需要系统资源、空间和时间。因此,从长远来看,尽可能避免在循环中声明它们。

        【讨论】:

          【解决方案5】:
          StringBuffer sb = new SringBuffer();
          // do something wiht it
          sb = new StringBuffer();
          

          我认为这段代码更快。

          【讨论】:

          • 这会有性能问题。它在每次迭代后创建一个新对象
          • @AdityaSingh 这是一个非常合理的方法。不要在没有证据的情况下假设性能问题。
          • 基于对正在发生的事情的理解来假设事物是智能的基础。
          【解决方案6】:

          重用StringBuffer最简单的方法是使用setLength()方法

          public void setLength(int newLength)

          你可能有这样的情况

          StringBuffer sb = new StringBuffer("HelloWorld");
          // after many iterations and manipulations
          sb.setLength(0);
          // reuse sb
          

          【讨论】:

          【解决方案7】:

          我建议为每次迭代创建一个新的StringBuffer(或者更好的是StringBuilder)。性能差异确实可以忽略不计,但您的代码会更短更简单。

          【讨论】:

          • 如果您有任何证据表明存在这种性能差异,请分享。 (我也很高兴看到 Java 最常用的地方的统计数据,以及“最常用”的定义。)
          • 众所周知,分配(Java 中的 new 关键字)比仅更改同一对象的某些字段更昂贵。对于您可以高度替换的“大部分”,有超过 15 亿台 Android 设备都使用 Java。
          • 我同意在某些情况下,代码的可读性比性能更重要,但在这种情况下,它只是一行代码!你可以运行一个基准测试来证明分配和对象创建,加上垃圾收集比不做更昂贵。由于我们处于循环中,因此它不仅相关。
          • 我也赞同 Knuth 的观点,但他的观点并不总是正确的。添加 一行 以潜在地获得 CPU 周期和内存绝对不是邪恶的。你的想法太直接了。请注意,一个循环通常会重复多次。一个循环可以重复数千次,如果不仔细优化,可能会在移动设备(以及服务器或计算机)上消耗宝贵的兆字节。
          • 我认为我们俩都已经足够清楚地表达了我们的观点,我觉得进一步的讨论对这个 cmets 部分没有好处。如果您认为我的回答不正确、具有误导性或不完整,那么欢迎您或任何人对其进行编辑和/或投反对票。
          【解决方案8】:

          一种选择是使用删除方法,如下所示:

          StringBuffer sb = new StringBuffer();
          for (int n = 0; n < 10; n++) {
             sb.append("a");
          
             // This will clear the buffer
             sb.delete(0, sb.length());
          }
          

          另一个选项(位更清洁)使用 setLength(int len)

          sb.setLength(0);
          

          更多信息请见Javadoc

          【讨论】:

          • 在循环中声明 StringBuffer 是一种不那么垃圾的事情。
          • 啊,我想 sb.setLength(0);比在循环中声明它更干净,更有效。您的解决方案违背了使用 StringBuffer 的性能优势...
          • 我认为性能优势来自字符串的可变性,而不是保存实例化。这是 1e8 次迭代的快速测试:内部循环(2.97 秒):ideone.com/uyyTL14w,外部循环(2.87 秒):ideone.com/F9lgsIxh
          • 说到性能:除非你的代码在多线程场景中被访问,否则你应该使用StringBuilder而不是StringBuffer——见javadoc:“如果可能,建议优先使用这个类到 StringBuffer,因为它在大多数实现下会更快”。
          • 在外部创建 SB 的唯一好处是不会丢失它的内部(可能很长)char[]。如果在第一个迭代器中它足够长,第二个循环将不需要调整任何 char[] 的大小。但是为了获得优势,“清除方法”必须保留内部数组的大小。 setLength 会这样做,但它也会将 SB 中所有未使用的字符设置为 \u0000,因此仅创建具有良好初始容量的新 SB 的性能较低。在循环内部声明更好。
          【解决方案9】:
          buf.delete(0,  buf.length());
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-10-12
            • 2011-04-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多