1

StringBuffer's SourceCode has a variable toStringCache, but only in the toString() method does it get a value:

public synchronized String toString() {
        if (toStringCache == null) {
            toStringCache = Arrays.copyOfRange(value, 0, count);
        }
        return new String(toStringCache, true);
    }

Why not use toString like StringBuilder:

return new String(value, 0, count); 

Is there any particular reason for this difference?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
HbnKing
  • 1,762
  • 1
  • 11
  • 25
  • what java version are you using ? – Ousmane D. Dec 01 '18 at 16:25
  • I am not sure why you want to know this, but the difference between the StringBuilder and StringBuffer is that the first one is not thread safe, and was introduced in java 1.5 as a replacement of StringBuffer when used in a single thread. I guess the implementation differences will have to do with this. – Juan Dec 01 '18 at 16:33
  • @Aomine java1.8 – HbnKing Dec 01 '18 at 16:38
  • @Juan I will have a look at the version records later – HbnKing Dec 01 '18 at 16:43
  • 3
    some useful info here --> https://stackoverflow.com/questions/46294579/why-stringbuffer-has-a-tostringcache-while-stringbuilder-not – Ousmane D. Dec 01 '18 at 16:48
  • As an aside, note that both the code for StringBuilder toString and StringBuffer toString have been modified to some extent in JDK9. – Ousmane D. Dec 01 '18 at 16:50
  • @Aomine thanks a lot ,you provided very useful message to me – HbnKing Dec 01 '18 at 16:52
  • Please don't use StringBuffer was it was replaced by StringBuilder more than ten year ago, – Peter Lawrey Dec 01 '18 at 18:25
  • @Juan I am willing to bet any code using StringBuffer in a multithreaded way isn't using it correctly. ;) ie.e. even for multi-threaded you should use StringBuilder and do your own synchronization. – Peter Lawrey Dec 01 '18 at 18:26

2 Answers2

0

The toStringCache array is shared with the string created. This avoids copying the array content at each toString() call.

Since StringBuffer is synchronized it can ensure that the value array will not be modified during the call, and thus the shared array will not receive inconsistent data. StringBuilder, as an unsynchronized class, can not give this guaranty.

The following example might produce output "aa" if StringBuilder had the same toString() implementation as StringBuffer.

StringBuilder s = new StringBuilder("ab");

// Thread A, parallel with B
System.out.println(s.toString());

// Thread B, parallel with A
s.reverse();
aventurin
  • 2,056
  • 4
  • 26
  • 30
  • the value is also stored in its super class , it is synchronized – HbnKing Dec 01 '18 at 16:47
  • Correct, but imagine Thread A calls `StringBuilder.toString()`. Before the method returns Thread B modifies the content of the same `StringBuilder`. Then it may be possible that the array copy would copy an inconsistent state when thread A completes the call. – aventurin Dec 01 '18 at 17:05
0

Strings in java are immutable, meaning if you just call new String(char_array) it will make an internal immutable copy of the array. Any changes to the original char_array will not be reflected in the new string. StringBuilder, however, is using a package private constructor String(char[] value, boolean share). It actually allows it to use a shared array. But now it has to make sure this shared array is not modified. So it makes a copy and creates a string with it.

new String(value) would've worked just fine too, but then every call to StringBuilder.toString() will create a new copy of the array. So it's a performance optimization.

Denis Tulskiy
  • 19,012
  • 6
  • 50
  • 68