13.3.5. Efficiency
Suppose you want to parse a string into two parts that are separated by a comma. The pattern (.),(.) is
clear and straightforward, but it is not necessarily the most efficient way to do this. The first . will attempt
to consume the entire input. The matcher will have to then back up to the last comma and then expand the rest
into the second .. You could help this along by being clear that a comma is not part of the group:
([^,]),([^,]). Now it is clear that the matcher should only go so far as the first comma and stop,
which needs no backing up. On the other hand, the second expression is somewhat less clear to the casual user
of regular expressions.
You should avoid trading clarity for efficiency unless you are writing a performance critical part of the code.
Regular expressions are by nature already cryptic. Sophisticated techniques make them even more difficult to
understand, and so should be used only when needed. And when you do need to be more efficient be sure that
you are doing things that are more efficientas with all optimizations, you should test carefully what is actually
faster. In the example we give, a sufficiently smart pattern compiler and matcher might make both patterns
comparably quick. Then you would have traded clarity for nothing. And even if today one is more efficient
than the other, a better implementation tomorrow may make that vanish. With regular expressions, as with any
other part of programming, choosing optimization over clarity is a choice to be made sparingly.
13.4. The StringBuilder Class
If immutable strings were the only kind available, you would have to create a new String object for each
intermediate result in a sequence of String manipulations. Consider, for example, how the compiler would
evaluate the following expression:
public static String guillemete(String quote) {
return '«' + quote + '»';
}
If the compiler were restricted to String expressions, it would have to do the following:
quoted = String.valueOf('«').concat(quote)
.concat(String.valueOf('»'));
Each valueOf and concat invocation creates another String object, so this operation would construct
four String objects, of which only one would be used afterward. The others strings would have incurred
overhead to create, to set to proper values, and to garbage collect.
The compiler is more efficient than this. It uses a StringBuilder object to build strings from expressions,
creating the final String only when necessary. StringBuilder objects can be modified, so new objects
are not needed to hold intermediate results. With StringBuilder, the previous string expression would be
represented as
quoted = new StringBuilder().append('«')
.append(quote).append('»').toString();
This code creates just one StringBuilder object to hold the construction, appends stuff to it, and then