The String
class in Java provides a method intern()
. This blog post describes its use.
JVM maintains a pool of String objects. When same String literals are used in the code (see variables x and y in Listing 1), only one String object is created in the pool and multiple references to it are used to reduce memory consumption.
A String object created by concatenating strings can be added to this pool by calling its intern()
method. Using intern()
in code will cause less number of String objects to be created as the objects from the pool will get reused. The intern()
is a native method and possibly implements Flyweight design pattern which is GoF structural design pattern. If a string with the matching content already exists in the pool then the same string object will be referred otherwise a new string object will be added to the pool.
However, strings created using String constructor are not interned (see variable z in Listing 1).
Where this pool of strings is maintained varies with the JVM. The Java HotSpot JVM maintains this pool in the PermGen. IBM and Oracle JRockit JVMs do not have PermGen, instead they use a native heap.
When there are many strings used in the application, interning strings can reduce the creation of string objects which can lead to a performance improvement. Strings which are not referenced anymore in PermGen or native heap get garbage collected.
Occurrence of OutOfMemoryError
due to consumption of PermGen space by this string pool is very rare. If you are using many string literals or there are lot of strings which you are interning, then you can mitigate this risk by increasing the PermGen size. For optimum performance you can intern strings only when the possible string values are known and there are more string comparisons. This way you can also avoid the garbage collector thread running frequently to reclaim the memory in PermGen.
Impact on String equals()
The equals()
method of String class compares the string references first as equivalent to using ==. When the references are not same, then it compares the length and when the length is also same, then it compares both the strings character by character. Calling intern()
before comparing strings using equals()
, will give faster result when the strings are same, since the equals()
will return true after finding the same references.
Though the string comparison can be done using == after calling intern()
, the explicit use of == operator to compare strings in code should be avoided and use of equals()
method should be preferred for the following reasons:
- The
equals()
method internally uses ==. - Developers should not get habituated to use == for string comparison as
equals()
is the appropriate way for doing it. Forgetting theintern()
call before use of == will lead to undesired results.
Listing 1 given below demonstrates the use of String intern()
.
String x = "abc"; String y = "abc"; String z = new String("abc"); System.out.println(x == y); //true System.out.println(x == z); //false z.intern(); System.out.println(x == z); //false String s = "Hello" + " World"; s.intern(); System.out.println("Hello World" == s); //true
Listing 1. Use of String intern() method
Using interned String as Map key
When only interned strings are used as a Map key, using IdentityHashMap
as a Map implementation can improve performance since it only compares the key references (equivalent to using == instead of equals()
).