Why are Strings immutable?

String in Java represents an immutable sequence of characters. When a String object is created, its value must be specified and it’s set in stone. Behind the scenes, a character array of the exact required size is created and initialized. String class does provide methods that seem to manipulate the value represented by the String object, e.g. replace(), substring(), toUpperCase(). These methods, however, don’t modify the object on which they are invoked. They return a new String object representing the modified value.

String s = "Immutable";
System.out.println("s: " + s);


s: Immutable

Why are Strings immutable? The simplest answer is: because they were designed to serve as value objects. They represent the value they hold. You need a different object if you want a different value. But why were Strings designed to serve as value objects? Strings are most commonly used as constants. Sometimes critical operations depend on the assumption that the value of String will not change behind their back. In other words, they need the String to be value object. StringBuilder and StringBuffer classes offer mutable strings if you need them. Lets look at cases where immutability of strings is required as well as how it benefits us generally.

1. Security

Security demanded String to be a value object. Here’s what James Gosling, the father of Java, has to say:

One of the things that forced Strings to be immutable was security. You have a file open method. You pass a String to it. And then it’s doing all kind of authentication checks before it gets around to doing the OS call. If you manage to do something that effectively mutated the String, after the security check and before the OS call, then boom, you’re in. But Strings are immutable, so that kind of attack doesn’t work. That precise example is what really demanded that Strings be immutable.

2. Performance

Strings are widely used as constants. The Java compiler – javac, which was written in Java itself, uses Strings heavily during its operation. Making the String immutable gives a chance to optimize String‘s implementation to perform well under such uses.

After an object is passed to a method, if the method wants to be sure that nobody else who has a reference to the same object will change the value of the object while it is using it, the method will have to make a local copy of the object. This adds memory as well as cpu cycle overhead. But since Strings are immutable, there’s no need to do this when dealing with Strings.

Also, multiple threads can share Strings without needing any synchronization overhead. Since Strings are immutable, there can be no race conditions.

3. Caching

Immutable objects can be cached, thereby saving memory. The String class indeed maintains a cache of all String objects created using a literal. This is called Interning.

String s1 = "Java";
String s2 = "Java"
System.out.println("s1 == s2: " + (s1 == s2));


s1 == s2: true

Both s1 and s2 were created using String literals and point to the same object which exists in the String cache.

Using the new operator to create a String forces creation of a new String object. However, the intern() method of String class returns the cached String object with the same value i.e. the interned object:

String s1 = "Java";
String s2 = new String("Java");
String s3 = s2.intern();

System.out.println("s1 == s2: " + (s1 == s2));
System.out.println("s1 == s3: " + (s1 == s3));


s1 == s2: false
s1 == s3: true

Why would you want to want to use interned Strings apart from the memory advantage they provide? One interesting consequence of interning is that Strings can be tested for value equality simply by testing the equality of the object references. So you can replace costly equals() comparisons by the cheap == comparisons. This could prove to be a huge advantage, for example, in algorithms that need to make lots of String comparisons.