从StringBuilder转换为toString的Java替代方案

时间:2012-07-08 19:18:21

标签: java string memory stringbuilder

我有这段代码将StringBuilders的ArrayList转换为字符串的ArrayList:

代码:

public ArrayList<String> convGenSeqToString(ArrayList<StringBuilder> buff){
        ArrayList<String> convBuf = new ArrayList<String>();

        for (StringBuilder xVar: buff){
            convBuf.add(xVar.toString());
        }
        return convBuf;
    }

我的代码适用于15-20MB文本文件的文件。但是我有一个44MB的文本文件,每当我用该文本文件运行我的程序时,我总是会收到此错误。

错误:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:2746)
    at java.util.ArrayList.ensureCapacity(ArrayList.java:187)
    at java.util.ArrayList.add(ArrayList.java:378)
    at Recognition.convGenSeqToString(Recognition.java:157)
    at Recognition.genSeq(Recognition.java:145)
    at Recognition.Recognitions(Recognition.java:96)
    at ChainDetection.main(Detection.java:25)

我已经使用-Xmx2048M增加了JVM运行配置中的内存,但仍然存在相同的错误。我将错误指向上面显示的代码并突出显示这一行:

convBuf.add(xVar.toString());

有没有其他方法可以在不使用.toString()方法的情况下将StringBuilder转换为字符串?我在其他论坛中看到过,他们也为toString创建了自定义类,但我还不熟悉泛型和一些“@”关键字。任何人都有如何解决这个问题的建议或指导?

被修改

我根据vanza的建议编辑了我的代码 这是:

public ArrayList<String> convGenSeqToString(ArrayList<StringBuilder> buff){
        ArrayList<String> convBuf = new ArrayList<String>(buff.size());
        Iterator <StringBuilder> iterBuf = buff.iterator();

        while (iterBuf.hasNext()){
            StringBuilder x = iterBuf.next();
            convBuf.add(x.toString());
            iterBuf.remove();
        }
        return convBuf;
    }

错误讯息:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.ArrayList.<init>(ArrayList.java:132)
    at Recognition.convGenSeqToString(Recognition.java:154)
    at Recognition.genSeq(Recognition.java:145)
    at Recognition.Recognitions(Recognition.java:96)
    at ChainDetection.main(ChainDetection.java:25)

我用buff.size()和没有buff.size()尝试了这个,我收到了同样的错误信息。但似乎我的错误消息现在减少到5。还有其他想法吗?提前谢谢!

2 个答案:

答案 0 :(得分:5)

如果不了解您的计划,我将不会对您采取的方法发表任何评论,只会对您发布的代码发表评论。听起来很奇怪,44MB的文件正在填满2G堆。

您可以做的一件事是预先在目标数组中分配空间:

ArrayList<String> convBuf = new ArrayList<String>(buf.size());

这将避免ArrayList调整大小步骤,该步骤会创建现有列表的副本(并显示在堆栈跟踪中)。

您可以尝试的另一件事是在构建String数组时释放对原始StringBuilders的引用。使用Iterator(而不是“for each”循环),并在每次迭代时使用buffIterator.remove()数组中删除StringBuilder;这样你就可以释放一些内存,让垃圾收集器在你内存不足时回收。

但是,再次,你用这么小的文件耗尽内存听起来很奇怪。也许用jvisualvm查看你的堆可能会有所帮助。

答案 1 :(得分:1)

有两种方法可以从StringBuilder获取值

  1. 首先使用Reflection并调用package protected方法 getValue()这很难,我认为不是那么好。
  2. 第二次通话方法getChars
  3. 顺便说一句,你将拥有字符数组,并且使用string你将创建字符串的新实例,它将使用你的记忆。