- 99 - The advantages of
String
s can be summed up as ease of use, internationalization support, and compatibility to existing interfaces. Most methods expect a
String
object rather than a
char
array, and
String
objects are returned by many methods. The disadvantage of
String
s boils down to inflexibility. With extra work, most things you can do with
String
objects can be done faster and with less intermediate object-creation overhead by using your own set of
char
array manipulation methods.
For most performance tuning, you pinpoint a bottleneck and make localized changes to objects and methods that speed up that bottleneck. But
String
tuning often involves converting to
char
arrays, whereas you rarely come across
public
methods or interfaces that deal in
char
arrays. This makes it difficult to switch between
String
s and
char
arrays in any localized way. The consequences are that you either have to switch back and forth between
String
s and
char
arrays, or you have to make extensive modifications that can reach across many application boundaries. I have no easy
solution for this problem.
String
tuning can get messy. It is difficult to handle
String
internationalization capabilities using raw
char
arrays. But in many cases, internationalized
String
s form a specific subset of
String
usage in an application, mainly in the user interface, and that subset of
String
s rarely causes bottlenecks. You should differentiate between
String
s that need internationalization and those that are simply processing characters, independent of language. These latter
String
s can be replaced for tuning with
char
arrays.
[2]
Internationalization-dependent
String
s are more difficult to tune, and I provide some examples of tuning these later in the chapter. Note also that internationalized
String
s can be treated as
char
arrays for some types of processing without any problems; see Section 5.4.2
later in this chapter.
[2]
My editor summarized this succinctly with the statement, Avoid using
String
objects if you dont intend to represent text.
5.2 Compile-Time Versus Runtime Resolution of Strings
For optimized use of
String
s, you should know the difference between compile-time resolution of
String
s and runtime creation. At compile time,
String
s are resolved to eliminate the concatenation operator if possible. For example, the line:
String s = hi + Mr. + + Buddy;
is compiled as if it read:
String s = hi Mr. Buddy;
However, suppose you defined the
String
using a
StringBuffer
:
String s = new StringBuffer .appendhi . appendMr. .append .appendBuddy.toString ;
Then the compiler cannot resolve the
String
at compile time. The result is that the
String
is created at runtime along with a temporary
StringBuffer
. The version that can be resolved at compile time is more efficient. It avoids the overhead of creating a
String
and an extra temporary
StringBuffer
, as well as avoiding the runtime cost of several method calls. However, when an expression involving
String
concatenation cannot be resolved at compile time, the concatenation must execute at runtime. This causes extra objects to be generated. For example,
consider the following method:
- 100 -
public String sayHiString title, String name {
return hi + title + + name; }
The
String
generated by this method cannot be resolved at compile time because the variables can have any value. The compiler is free to generate code to optimize the
String
creation, but it does not have to. Consequently, the
String
-creation line could be compiled as:
return new StringBuffer .appendhi . appendtitle.append .appendname.toString ;
This is optimal, creating only two objects. On the other hand, the compiler could also leave the line with the default implementation of the concatenation operator, which is equivalent to:
return hi .concattitle.concat .concatname;
This last implementation creates two intermediate
String
objects that are then thrown away, and these are generated every time the method is called.
So, when the
String
can be fully resolved at compile time, the concatenation operator is more efficient than using a
StringBuffer
. But when the
String
cannot be resolved at compile time, the concatenation operator is less efficient than using a
StringBuffer
. One further point is that using the
String
constructor in a
String
definition forces a runtime string creation:
String s = new Stringhi + Mr. + + Buddy;
is compiled as:
String s = new Stringhi Mr. Buddy;
This line uses the compile-time resolved string as a parameter for the
String
constructor to create a new
String
object at runtime. The new
String
object is equal but not identical to the original string:
String s = new Stringhi Mr. Buddy; s == hi Mr. Buddy; is false
s.equalshi Mr. Buddy; is true
5.3 Conversions to Strings