Java StringBuilder - 重置或创建一个新的

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18766780/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 10:51:53  来源:igfitidea点击:

StringBuilder - Reset or create a new

javastringbuilder

提问by Chandru

I have a condition that a StringBuilder keeps storing lines matching a pattern from a large flat file (100's of MB). However after reaching a condition I write the content of the StringBuilder varialble to a textfile.

我有一个条件,即 StringBuilder 不断存储与大型平面文件(100 MB)中的模式匹配的行。但是,在达到条件后,我将 StringBuilder 变量的内容写入文本文件。

Now I wonder if I should use the same variable by resetting the object ->

现在我想知道是否应该通过重置对象来使用相同的变量 ->

stringBuilder.delete(0,stringBuilder.length())

OR

或者

stringBuilder=new StringBuilder();

Please suggest which would do you think is better as far as both performance and OOM issues are concerned.

请建议您认为就性能和 OOM 问题而言哪个更好。

采纳答案by anubhava

I think StringBuilder#delete(start, end)is still expensive call, you should do:

我认为StringBuilder#delete(start, end)仍然是昂贵的电话,你应该这样做:

stringBuilder.setLength(0);

to reset it.

重置它。



UPDATE:After looking at source code of StringBuilderIt seems setLength(int)leaves old buffer intact and it is better to call: StringBuilder#trimToSize()after above call which attempts to reduce storage used for the character sequence.

更新:在查看It 的源代码后StringBuilder,似乎setLength(int)旧缓冲区完好无损,最好调用:StringBuilder#trimToSize()在上面调用 which 之后attempts to reduce storage used for the character sequence

So something like this would be more efficient:

所以这样的事情会更有效率:

stringBuilder.setLength(0); // set length of buffer to 0
stringBuilder.trimToSize(); // trim the underlying buffer

回答by arshajii

Well there's a greater difference between the two. The first retains whatever capacity it had before you deleted the characters (i.e. stringBuilder.capacity()) whereas the second creates a new StringBuilderwith the default capacity, 16. Of course you could just pass stringBuilder.capacity()as an argument to the constructor, but it's important to understand the distinction here, nonetheless.

那么两者之间的差异更大。第一个保留在删除字符之前的任何容量(即stringBuilder.capacity()),而第二个创建一个StringBuilder默认容量为 16的新容量。当然,您可以将其stringBuilder.capacity()作为参数传递给构造函数,但了解这里的区别很重要,尽管如此。

In any case, I highly doubt that you will see a substantial performance difference between these two variants, so choose whichever is more readable and easier to manage. Onlywhen you've conclusively determined that this is causing some sort of bottleneck should you change your approach.

无论如何,我非常怀疑您是否会看到这两种变体之间存在显着的性能差异,因此请选择更具可读性和更易于管理的那个。只有当您最终确定这会导致某种瓶颈时,您才应该改变您的方法。

回答by vikingsteve

Imho, I would suggest to use new:

恕我直言,我建议使用新的:

stringBuilder = new StringBuilder();

I've never heard about a memory leak in StringBuilder, but when you really push the limits you never know. I would hedge my bets against it by using a new instance every time.

我从未听说过 StringBuilder 中的内存泄漏,但是当您真正突破极限时,您永远不知道。我会通过每次使用一个新实例来对冲我的赌注。

In the worst case maybe you lose some efficiency and the gc gets a workout, but you rule out the OOM possibility.

在最坏的情况下,您可能会失去一些效率并且 gc 得到锻炼,但您排除了 OOM 的可能性。

Because of that, and also for reasons of clarity I would personally take the new approach.

正因为如此,也为了清楚起见,我个人将采用新方法。

回答by Bohemian

I would use:

我会用:

 stringBuilder = new StringBuilder();

because if you fill it with a large amount of data, calling stringBuilder.setLength(0);won't unallocate the backing array, so you could see memory usage stay high unnecessarily.

因为如果用大量数据填充它,调用stringBuilder.setLength(0);不会取消分配后备数组,因此您可能会看到内存使用率不必要地居高不下。

Also, it's just easier to read and understand.

此外,它更容易阅读和理解。

回答by jpayne

If you are in a tight loop and you will continue back in that loop after you write the data to the file, you should definitely re-use the StringBuilder. There's no reason not to and it's better than churning the GC. If you were writing this in C or C++ you would re-use the buffer.

如果您处于紧密循环中,并且在将数据写入文件后将继续返回该循环,则绝对应该重新使用 StringBuilder。没有理由不这样做,这比搅动 GC 更好。如果您用 C 或 C++ 编写它,您将重新使用缓冲区。

Also, while true that the delete(...) method calls System.arraycopy, the number of bytes copied is 0 so it's insignificant.

此外,虽然 delete(...) 方法调用 System.arraycopy 是正确的,但复制的字节数为 0,因此它无关紧要。

Ah - somebody else mentioned me that there is a setLength(...) method which is the fastest way to re-use the buffer.

啊 - 其他人提到我有一个 setLength(...) 方法,这是重新使用缓冲区的最快方法。

回答by user3241961

One fundamental difference is sb.delete keeps the reference, while the constructor loses it.

一个根本区别是 sb.delete 保留引用,而构造函数丢失它。

If your SB is a method argument, and is supposed to be used to pass content back to the caller, you have to use sb.delete. The caller holds the original reference.

如果您的 SB 是一个方法参数,并且应该用于将内容传递回调用者,则您必须使用 sb.delete。调用者持有原始引用。

回答by Akhil Dad

Ideally we should use new StringBuilder()Digging a bit in StringBuilder class from grepcodeI get to know the following.

理想情况下,我们应该new StringBuilder()grepcode在 StringBuilder 类中使用Digging我了解以下内容。

Creating new object :

创建新对象:

/**
     * Creates an AbstractStringBuilder of the specified capacity.
     */
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

new StringBuilder() creates a new object with initial capacity char array. Overhead here : GC will be called for clearing older object.

new StringBuilder() 创建一个具有初始容量字符数组的新对象。这里的开销:将调用 GC 来清除旧对象。

Using delete :

使用删除:

public AbstractStringBuilder delete(int start, int end) {
        if (start < 0)
            throw new StringIndexOutOfBoundsException(start);
        if (end > count)
            end = count;
        if (start > end)
            throw new StringIndexOutOfBoundsException();
        int len = end - start;
        if (len > 0) {
            System.arraycopy(value, start+len, value, start, count-end);
            count -= len;
        }
        return this;
    }

Using Length and TrimToSize :

使用 Length 和 TrimToSize :

public void trimToSize() {
        if (count < value.length) {
            value = Arrays.copyOf(value, count);
        }
    }

Will call copyOf From array class

将从数组类调用 copyOf

public static char[] copyOf(char[] original, int newLength) { char[] copy = new char[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }

public static char[] copyOf(char[] original, int newLength) { char[] copy = new char[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); 返回副本;}

Now it will also call System.arrayCopywhich is a native method. Now if you see in copyOf we are creating a new charArray again of 0 length, and when we try to add again data to it, it will call expandbecause the current length would be 0. So I think its better to call new StringBuilder()

现在它还会调用System.arrayCopy,这是一个本地方法。现在,如果您在 copyOf 中看到我们再次创建一个长度为 0 的新 charArray,并且当我们尝试再次向其中添加数据时,它将调用 expand因为当前长度将为 0。所以我认为最好调用 new StringBuilder()

You can see the above code on grepcode

你可以在grepcode上看到上面的代码

PS : @user3241961 is write in case you are using reference of this object then new would require to set it again

PS:@user3241961 是写,以防您使用此对象的引用,然后 new 将需要再次设置它

回答by jmlotero

It is cheaper reuse the created object than allocate a new one, always. It also avoids extra work for the Garbage Collector, as you are handling only an object.

重用创建的对象总是比分配一个新对象更便宜。它还避免了垃圾收集器的额外工作,因为您只处理一个对象。

The faster way is:

更快的方法是:

stringBuilder.setLength(0);