How do StringBuffer () and StringBuilder () behave?

11

Problem and Mystery:

StringBuffer y = new StringBuffer("Eduardo");

I'm using a StringBuffer because I need to add some values to it later. I was debugging and noticed that there is a blanks at the end. Notice the image:

Image 1: Additional spaces in the StringBuffer.

The same happens when I use StringBuilder , does anyone know why these spaces are incremented?

There are some aspects between StringBuilder and StringBuffer . How to use Builder when it does not Thread . I believe I have not invested.

    
asked by anonymous 27.02.2014 / 22:17

4 answers

14

Blanks are meant to improve performance when concatenating Strings. That's why it's a buffer.

For example: if you concatenate two Strings like this: "abc" + "def", Java will create, in addition to these two String objects, a third object containing the result "abcdef". However, when using the buffer, Java will throw chars 'd', 'and' and 'f' into the empty spaces of the buffer and update that 'count' of its shape to reflect the new size of the set. This is a much faster operation.

If blanks are not sufficient, Java will automatically increase the buffer size for you.

This size, incidentally, you can configure at builder . This is good because it costs a bit (in terms of performance) for Java to resize the buffer.

    
27.02.2014 / 22:22
12

The hierarchy

The classes java.lang.StringBuffer and java.lang.StringBuilder have exactly the same interface extend java.lang.AbstractStringBuilder , which has two main attributes:

char value[];
int count;

There are stored the characters and the actual size of the characters.

About the Buffer

String is a type that stores a character set. It is immutable, that is, it can not have the modified content as well as its size.

The problem with this is that to create new Strings, for example, by concatenating two or more Strings, a new String as the total size of them must be created in memory. If multiple such operations are performed in sequence, the JVM will need to allocate new memory blocks and run the Garbage Collector to deallocate what is not used at all times. This is very "costly" in terms of performance.

The StringBuffer appears to solve the problem. A% w / of% is nothing more than a String with a Buffer , that is, a placeholder for new characters that can be modified and makes unnecessary, allocate more memory at all times.

The buffer is simply a vector of characters larger than the actual content. For example, the buffer can have 1000 positions and the actual String only 500. This is controlled by the StringBuffer attribute. In this example, we could add up to 500 more characters without degrading program performance.

The initial size

In many situations it is important to set the initial size of the buffer to an average size of what you want to use.

By doing count or new StringBuffer() , that is, without setting an initial size, we are underutilizing the class. The initial capacity of the buffer is only 16 characters.

This means that if we add more than 16 characters, a new buffer will have to be allocated.

Increasing size

When bursting buffer capacity the next one will be created twice as large. See the calculation of the new buffer capacity in the new StringBuilder() method of the expandCapacity class:

void expandCapacity(int minimumCapacity) {
    int newCapacity = (value.length + 1) * 2;
    if (newCapacity < 0) {
        newCapacity = Integer.MAX_VALUE;
    } else if (minimumCapacity > newCapacity) {
        newCapacity = minimumCapacity;
    }
    value = Arrays.copyOf(value, newCapacity);
}

AbstractStringBuilder or StringBuffer ?

This is a common question. Look at the Javadoc (links are at the beginning of the answer) and note that both have exactly the same interface, that is, the same methods and method signatures.

What's the difference? Let's look at a basic method in both versions, StringBuilder .

The version in append(String) is:

public StringBuilder append(String str) {
    super.append(str);
    return this;
}

And the version in StringBuilder is:

public synchronized StringBuffer append(String str) {
    super.append(str);
    return this;
}

Did you notice the difference? It's the StringBuffer !

We say that the class synchronized is synchronized , while the StringBuffer class is not synchronized .

Synchronized vs. Not Synced

What are the advantages and disadvantages of being synchronized or not?

When a class is synchronized, it is best suited to work in multithreaded environments, for example, on an application server that serves multiple users at the same time. Imagine multiple threads writing a log in memory, for example.

In this case, only one thread at a time can add content to StringBuilder . The problem is that this also generates unwanted blocks in execution, because we are not always modifying the class.

If multiple threads just want to read some information from the class, then the synchronization is delaying them for no reason. Just to cite an example, class StringBuffer has the search method StringBuffer synchronized.

Already when a class is not synchronized, it is not suitable to be used concurrently by more than one thread, however it obtains the maximum of use to be modified by a single thread and also to be used in the multi-reading mode threads.

As a general rule, if the object will be used only in the scope of a method, not being shared, it is always opted for indexOf , which was created just for this purpose.

If the object is shared in some way with other classes and it is possible for someone to use it in multiple tiers, StringBuilder is more appropriate.

This rationale applies to several other classes in the JVM. See, for example, the Hashtable classes, StringBuffer (not synchronized) and HashMap (synced only for change but not for reading).

So it's obvious the importance of getting to know the APIs of the language before leaving, always using the same solutions indiscriminately.

For more details, see my another answer here in SO .

    
16.05.2014 / 18:14
6

This is related to the default sizes and the way the internal buffer is incremented, for both StringBuffer and StringBuilder .

You can see this because you are inspecting the value field of the object, where the string is built and stored. Note, however, that the actual length of your string is kept in the count field.

    
27.02.2014 / 22:22
5

Just to add, if you look at class StringBuilder it looks like this:

/**
 * Constructs a string builder that contains the same characters
 * as the specified <code>CharSequence</code>. The initial capacity of
 * the string builder is <code>16</code> plus the length of the
 * <code>CharSequence</code> argument.
 *
 * @param      seq   the sequence to copy.
 * @throws    NullPointerException if <code>seq</code> is <code>null</code>
 */
public StringBuilder(CharSequence seq) {
    this(seq.length() + 16);
    append(seq);
}

public StringBuilder append(Object obj) {
    return append(String.valueOf(obj));
}

public StringBuilder append(String str) {
    super.append(str);
    return this;
}

Notice that in the constructor it leaves 16 characters blank initially, exactly the amount of white space that is after Eduardo , in its example. This is the size that is left as buffer by default, but as stated in another answer you can pass the initial size in StringBuffer or StringBuilder .

This space left over makes size not necessarily change with each insertion of values in your object, and at the same time does not have a large enough left over to consume significant memory space.

    
28.02.2014 / 13:23