⬆️ ⬇️

StringBuffer, and how hard it is to get rid of the legacy of the old code

Hello. This article is a free translation of the StringBuffer post , and get rid of the legacy code . Somehow he was very impressed with me, so I decided to translate. Go.



In 2006, StringBuilder appeared in the 5th java. More lightweight and reasonable alternative to StringBuffer . Here is what the official StringBuffer documentation StringBuffer :



This class is supplemented by a similar class intended for use in one stream - StringBuilder. In general, you should give preference to the StringBuilder class, since it supports all the same operations as this (StringBuffer), but faster, because it does not perform any synchronization.


Having synchronized in StringBuffer has never been a good idea at all. The main problem is that one operation is never enough. A single .append(x) concatenation is useless without other operations, such as .append(y) and .toString() . At a time when each particular method is thread-safe, you cannot make multiple calls without contention between threads. Your only option is external sync.

')

So that? So, 10 years later, no one uses StringBuffer !? Well, at least, definitely not for the new functionality!?



How many objects does this code create?



As I wrote earlier, the virtual machine creates many objects at the start or when loading the main libraries. Much more than you could imagine by asking the question above:



 public class Main { public static void main(String... args) { System.out.println("Hello " + "world"); } } 


Oracle JVM Version 8 creates approximately 10_000 objects to run this program.



How much does StringBuffers create?



So, to run a JVM you need to create a lot of objects, but the old classes that have a faster alternative that shouldn't be used for 10 years, right?



 public class Main { public static void main(String[] args) throws IOException { System.out.println("Waiting"); System.in.read(); } } 


While the process is running, we can execute the following command:



 jmap -histo {pid} | grep StringBuffer 


and we get:



  18: 129 3096 java.lang.StringBuffer 


129 is the number of StringBuffer objects that Java 8 Update 121 has created. This is less than the last time I checked, but still, a little surprising.



(I checked Java 131 update 131, I got a total of 14 objects).



And what about new features - lambdas and streams? They were created explicitly in the last 10 years and use some third-party libraries, like Objectwebs ASM. And these developers precisely know the insides of the virtual machine and should have designed the new features as lightweight as possible.



 public class Main { public static void main(String[] args) throws IOException { IntStream.range(0, 4).forEach(System.out::println); System.out.println("Waiting"); System.in.read(); } } 


Run jmap again and what do we see?



  17: 545 13080 java.lang.StringBuffer 


Additional 416 objects for the simplest lambda and stream!



(Again, I checked Java 8 update 131 and got 430 objects, that is, the difference in the same 416 objects. It seems that the stream and lambda were not cleaned up).



By the way, the program above generally creates:



 Total 35486 4027224 


or 35_486 objects!



findings



Of course, using the StringBuffer at the start of the application does not make much difference, but knowing that there is a suitable alternative and the StringBuffer is still used even in new features — it shows how difficult it is to get rid of the legacy of the old code or change the way people use the best practices.



PS

In the original post they left a link to the cleaning ticket from StringBuffer in 9-ke.

So it is quite possible in 3 months we will be left without a legacy :), the truth is only about StringBuffer . Do not forget about Vector , Hashtable and other amenities.

Source: https://habr.com/ru/post/329956/



All Articles