Skip to content
Theory · Strings · lesson 3 of 11

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:

JAVA
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:

  1. name.replace('a', 'o') creates a new string onno, where every a is replaced with o. But it is put nowhere, so it is lost.
  2. The first println(name) prints anna: the string name has not changed.
  3. String other = name.replace('a', 'o'); creates the string onno again and this time puts it into other.
  4. println(other) prints onno.
  5. The last println(name) prints anna: 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() and toLowerCase();
  • 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:

JAVA
String city = "paris";
String before = city;
city = city.toUpperCase();
System.out.println(city);   // PARIS
System.out.println(before); // paris

Line by line:

  1. String city = "paris"; puts into city a reference to the string paris. A variable of type String, like an array variable, holds a reference to the object, not the object itself: not the card but a ticket to it.
  2. String before = city; copies the reference: both variables lead to the same string paris.
  3. city = city.toUpperCase(); creates a new string PARIS and puts a reference to it into city.
  4. println(city) prints PARIS.
  5. println(before) prints paris: before leads 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:

  • final forbids the variable to get a new value, that is, a different reference;
  • immutability forbids changing the string itself.
JAVA
final String greeting = "hi";
greeting = greeting.toUpperCase(); // ✗
TEXT
error: cannot assign a value to final variable greeting

You 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:

JAVA
String input = "  yes ";
input.strip(); // ✗
System.out.println(input.length()); // 6

The 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 String holds a reference; assignment changes the reference, not the string.
  • final forbids changing the variable, and immutability forbids changing the string itself.