Who cares about the performance of ToString? No one! Unless you have a lot of data in bulk processing, using ToString produces a lot of logs. Then you investigate why it's so slow to realize that most of the ToString methods use introspection, which can actually be optimized.
But first let's take a look at what Javadoc recalls object.tostring should do: "Returns the string representation of the object, which must be concise but well-articulated. It is recommended that all subclasses override this method. The most interesting thing here is "concise" and "informative". Our beloved Ides often generate equals/hashcode/tostring of these methods for us, and we usually do not control them. In addition, these Ides provide many ways to generate our own ToString: String connections (using the + sign), StringBuffer, StringBuilder, Tostringbuilder (Commons Lang 3), Reflectiontostringbuilder (Commons Lang 3), guava or objects.tostring ... Which one should I choose?
If you want to know what kind of tostring implementation will be more efficient, do not guess, but to test! At this point you need to use JMH. I've written about it on my blog, so there's no more detail about how JMH works.
In this benchmark, I created a complex object graph (using inheritance, collections, and so on), and I used all the different implementations of ToString generated by the IDE to see which performance was better. Just one rule of thumb: brevity. Regardless of which technology you use (below), generating tosting for some attributes or all attributes (including inheritance, dependencies, or collections) can have a huge impact on performance.
connect string with +
Let's start with the most efficient approach: connect strings with +. Once this is considered to be the use of evil ("Do not use + connection string!!! "), has become very cool and efficient! Now the JVM compiler (most of the time) compiles the + into a string builder. So, don't hesitate, use it. The only drawback is that the null value is not processed and you need to handle it yourself.
Take a look at the average performance calculated using JMH in the annotations below.
Public String toString () { return "myobject{" + "att1= '" + att1 + "+ ", att2= ' "+ att2 +" +< c6/> ", att3= '" + att3 + "+ Super. toString ();} // Average Performance with JMH (OPS/S) // (min, avg, max) = (140772,314, 142075,167, 143844,717) // average performance measured using the JMH // (min, avg, max) = (140772,314, 142075,167, 143844,717)
Connecting Strings with Objects.tostring
The
Java SE 7 brings up the objects class and some of its static methods. The advantage of objects.tostring is that it can handle null values and can even set a default value for NULL. Its performance is slightly lower than the previous, but the null value can be processed:
Public String toString () { return "myobject{" + "att1= '" + objects.tostring (ATT1) + "+ ", att2 = ' "+ objects.tostring (ATT2) + " + ", att3= '" + objects.tostring (ATT3) + "+ Super. toString ();} // Average Performance with JMH (OPS/S)// (min, avg, max) = (138790,233, 14079 1,365, 142031,847)// average performance measured with JMH // (min, avg, max) = (138790,233, 140791,365, 142031,847)
StringBuilder
Another technique is to use StringBuilder. It's hard to tell which technology is better. As I said earlier, I've used complex object graphs (ATT1, att2, and ATT3 variables for readability), JMH gives more or less the same result. The following three technologies are very close to performance.
PublicString toString () {FinalStringBuilder SB =NewStringBuilder ("myobject{"); Sb.append ("att1="). Append (ATT1). Append ("'); Sb.append (", att2= '"). Append (ATT2). Append (' '); Sb.append (", att3= '"). Append (ATT3). Append (' '); Sb.append (Super. toString ()); returnsb.tostring ();}//Average Performance with JMH (OPS/S)//(min, avg, max) = (96073,645, 141463,438, 146205,910)//average performance measured using the JMH//(min, avg, max) = (96073,645, 141463,438, 146205,910)
Guava
Guava has some helper classes: one of them can help you generate ToString. This is less than pure JDK API performance, but it can provide you with some additional services (I mean Guava):
PublicString toString () {returnObjects.tostringhelper ( This). Add ("Att1", ATT1). Add ("Att2", ATT2). Add ("Att3", ATT3). Add ("Super",Super. ToString ()). ToString ();}//Average Performance with JMH (OPS/S)//(min, avg, max) = (97049,043, 110111,808, 114878,137)//average performance measured using the JMH//(min, avg, max) = (97049,043, 110111,808, 114878,137)
Commons Lang3
Commons Lang3 has some techniques to generate ToString: from builder to Introspector. As you can guess, introspection is easier to use, with less code, but with poor performance:
PublicString toString () {return NewTostringbuilder ( This). Append ("Att1", ATT1). Append ("Att2", Att2). Append ("Att3", ATT3). Append ("Super",Super. ToString ()). ToString ();}//Average Performance with JMH (OPS/S)//(min, avg, max) = (73510,509, 75165,552, 76406,370)//average performance measured using the JMH//(min, avg, max) = (73510,509, 75165,552, 76406,370) PublicString toString () {returnTostringbuilder.reflectiontostring ( This, Tostringstyle.short_prefix_style);}//Average Performance with JMH (OPS/S)//(min, avg, max) = (31803,224, 34930,630, 35581,488)//average performance measured using the JMH//(min, avg, max) = (31803,224, 34930,630, 35581,488) PublicString toString () {returnReflectiontostringbuilder.tostring ( This);}//Average Performance with JMH (OPS/S)//(min, avg, max) = (14172,485, 23204,479, 30754,901)//average performance measured using the JMH//(min, avg, max) = (14172,485, 23204,479, 30754,901)
Summarize
Now with JVM optimizations, we can safely use the + to concatenate strings (and use objects.tostring to handle null). With a utility class built into the JDK, no external framework is required to handle null values. Therefore, the out-of-the-box JDK has better performance than the other technologies described in this article (if you have other frameworks/technologies, please leave a comment and I'll try it).
As a summary, here is a table of average performance data obtained from JMH (descending from the most efficient)
Use of Technology |
average number of Operations/sec |
Connect strings with ' + ' |
142.075,167 |
String Builder |
141.463,438 |
Objects.tostring |
140.791,365 |
Guava |
110.111,808 |
Tostringbuilder (Append) |
75.165,552 |
Tostringbuilder (reflectiontostring) |
34.930,630 |
Reflectiontostringbuilder |
23.204,479 |
Again, this is important if you call the ToString method often. Otherwise, performance is really not a thing.
Comparison of performance optimization schemes for Java ToString