Compile-Time Versus Runtime Resolution of Strings

- 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