Strings are immutable
In the previous lesson we printed the result of each method right away. But what happens if you call a method and put its result nowhere?
Think of the printed card again. You cannot correct a letter on it. You can only make a new card with the letters you need and hand it over instead of the old one. Every string method that looks like a change behaves this way:
public class Main {
public static void main(String[] args) {
String name = "anna";
name.replace('a', 'o');
System.out.println(name); // anna
String other = name.replace('a', 'o');
System.out.println(other); // onno
System.out.println(name); // anna
}
}Let's go through the program line by line:
name.replace('a', 'o')creates a new stringonno, where everyais replaced witho. But it is put nowhere, so it is lost.- The first
println(name)printsanna: the stringnamehas not changed. String other = name.replace('a', 'o');creates the stringonnoagain and this time puts it intoother.println(other)printsonno.- The last
println(name)printsanna: a new string has appeared, and the old one stayed as it was.
A string does not change
An object that cannot be changed after it is created is called immutable. A string in Java is immutable: none of its methods touches its characters. Methods that look like a change return a new string:
toUpperCase()andtoLowerCase();replace(…);strip();substring(…).
If you do not store the result of such a method, it is lost. The compiler does not warn you: in Java you may call a method and ignore its result.
The new value goes into the same variable
To get the changed text into the variable, you put the result back into it: name = name.toUpperCase();. The string still does not change here; the variable does. Let's see what that means:
String city = "paris";
String before = city;
city = city.toUpperCase();
System.out.println(city); // PARIS
System.out.println(before); // parisLine by line:
String city = "paris";puts intocitya reference to the stringparis. A variable of typeString, like an array variable, holds a reference to the object, not the object itself: not the card but a ticket to it.String before = city;copies the reference: both variables lead to the same stringparis.city = city.toUpperCase();creates a new stringPARISand puts a reference to it intocity.println(city)printsPARIS.println(before)printsparis:beforeleads to the old string, and nobody has changed it.
An array would behave differently: a write through one reference is visible through the other. That never happens with a string, because nobody can change its characters. += works the same way: city += "!" means city = city + "!" and also creates a new string.
The card picture is off here. In real life someone has to throw an unneeded card away. In Java, the JVM removes a string that no reference leads to from memory by itself.
Why strings are immutable
Interviewers often ask this. The main answer: an immutable string can be shared safely.
- Several variables can hold one string, and none of them can spoil it for the others.
- You can pass a string to a method: whatever the method does, your string stays the same.
- That is why Java can keep equal strings as one copy and save memory.
final is something else
The word final and the immutability of a string are often confused, but they forbid different things:
finalforbids the variable to get a new value, that is, a different reference;- immutability forbids changing the string itself.
final String greeting = "hi";
greeting = greeting.toUpperCase(); // ✗error: cannot assign a value to final variable greetingYou may create the string HI here, but you may not put it into a final variable.
Common mistake
A method is called, and its result is never stored:
String input = " yes ";
input.strip(); // ✗
System.out.println(input.length()); // 6The goal was to remove the spaces, but the length is still 6. The method strip() returned a new string yes, and it was lost. Store the result: after input = input.strip(); the call input.length() gives 3.
Key points
- A string is immutable: its methods do not change its characters, they return a new string.
- A method's result has to be stored, or it is lost:
name = name.toUpperCase();. - A variable of type
Stringholds a reference; assignment changes the reference, not the string. finalforbids changing the variable, and immutability forbids changing the string itself.