Craftstack Academy
Java

Java NullPointerException: Cannot invoke ... because ... is null

· 6 min read

Your first class compiles without a single complaint. You run it, and instead of the account you expected, Java prints this:

Terminal
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.toUpperCase()" because "this.owner" is null
	at Account.label(Account.java:10)
	at Account.main(Account.java:15)

Here is the program:

Account.java
public class Account {
    private String owner;
    private double balance;

    public Account(String owner) {
        owner = owner;
    }

    public String label() {
        return owner.toUpperCase() + ": " + balance;
    }

    public static void main(String[] args) {
        Account a = new Account("Alex");
        System.out.println(a.label());
    }
}

The compiler was happy, because nothing here breaks Java's rules. The problem only shows up while the program runs: a variable that should point to a String points to nothing.

What null means

A variable of a class type, like String, Account or Integer, doesn't hold the object itself. It holds a reference: directions to where the object is. null is the value for "no object at all".

You can store null, pass it around and print it. What you can't do is use it as if it were an object: call a method on it (owner.toUpperCase()), read a field from it, or ask for its length. Java has nothing to call the method on, so it stops with a NullPointerException, often shortened to NPE.

How to read the message

Since Java 15, the message tells you exactly what went wrong. Read the first line in two halves:

  • Cannot invoke "String.toUpperCase()": what Java was trying to do. It wanted to call toUpperCase() on a String.
  • because "this.owner" is null: which value was missing. The field owner of this object was null.

The at lines below tell you where, newest first: line 10 of Account.java, in the method label, which was called from main on line 15. Start at the top at line that names your own code.

Why owner is null here

Look at the constructor:

java
public Account(String owner) {
    owner = owner;
}

Inside the constructor there are two things called owner: the parameter, and the field of the object. The plain name means the parameter, so owner = owner; copies the parameter into itself. The field is never touched, and fields of a class type start as null. (Number fields start as 0, which is why balance printed fine.)

The fix is this.owner, which means "the field of this object":

java
public Account(String owner) {
    this.owner = owner;
}
Terminal
ALEX: 0.0

Four places beginners meet it

1. A field that was never set

That's the example above. Every field of a class type is null until something stores an object in it. If the message says because "this.something" is null, check the constructor: is the field set there, with this.?

2. An empty slot in an array

new String[3] makes an array with three slots, but no strings in them. Every slot starts as null:

Names.java
public class Names {
    public static void main(String[] args) {
        String[] names = new String[3];
        names[0] = "Ana";
        for (String name : names) {
            System.out.println(name.length());
        }
    }
}
Terminal
3
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "<local5>" is null
	at Names.main(Names.java:6)

The first name works (Ana has 3 letters), and the second slot is empty. Notice "<local5>": plain javac doesn't keep the names of local variables, so Java numbers them instead. Compile with javac -g (many code editors do this for you) and the message names the variable:

Terminal
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "name" is null

Fill every slot before you use it, or use an ArrayList, which only contains what you have added.

3. A key that isn't in the map

Map.get returns null when the key isn't there. That's fine until you put the result into an int:

Grades.java
import java.util.HashMap;
import java.util.Map;

public class Grades {
    public static void main(String[] args) {
        Map<String, Integer> scores = new HashMap<>();
        scores.put("Ana", 72);
        scores.put("Ben", 85);

        int score = scores.get("Robin");
        System.out.println("Robin: " + score);
    }
}
Terminal
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of "java.util.Map.get(Object)" is null
	at Grades.main(Grades.java:10)

This message looks strange, because your code never calls intValue(). Java does it for you: to turn an Integer object into a plain int, it calls intValue() on it. There's no Robin in the map, so get gave back null, and the hidden call failed. The message says so: "the return value of Map.get(Object) is null".

Keep the result as an Integer and check it, or ask for a default value:

java
Integer score = scores.get("Robin");
if (score == null) {
    System.out.println("No score for Robin");
} else {
    System.out.println("Robin: " + score);
}
System.out.println("Robin: " + scores.getOrDefault("Robin", 0));
Terminal
No score for Robin
Robin: 0

4. Comparing a string that might be null

java
String answer = null;
if (answer.equals("yes")) {
    System.out.println("OK");
}
Last line of the error
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because "<local1>" is null

Turn the comparison around and put the known text first: "yes".equals(answer). A real string is never null, and equals simply returns false when answer is null, so the program prints the else branch instead of crashing.

How to find any NullPointerException

  1. Read the first line: what Java tried to do (Cannot invoke "...") and which value was null (because "..." is null).
  2. Go to the top at line in your own code and find that value on that line.
  3. Ask where that value should have been set: a constructor, an array slot, a get call, a method that returns something. That's where the real bug is, usually a few lines earlier.
  4. Fix it there: set the field (with this.), fill the array, handle the missing key, or put the known value first in equals.

Avoid "fixing" it by wrapping everything in if (x != null). That hides the crash, but the value is still missing, and the program quietly does the wrong thing instead.

In the browser editor

In our courses, Java runs right in your browser. There, a NullPointerException shows without the detail after the colon, and the at lines end in (Unknown Source) instead of a file and line number. Use the method name in the top at line, like at Account.label, to find the place, then apply the same steps. On your own computer, you'll see the full message shown in this article.

The compiler catches a different kind of mistake before your program ever runs; the one almost everyone meets first is incompatible types: String cannot be converted to int. If you're still deciding whether Java is the right first language for you, see Which programming language should you learn first?

Python

Why does 0.1 + 0.2 not equal 0.3 in Python?

Why Python prints 0.30000000000000004 for 0.1 + 0.2, why 0.1 + 0.2 == 0.3 is False, and the three fixes: round for display, math.isclose() instead of ==, and Decimal for money. With code you can run.

· 4 min read

Learn by writing the code yourself.

Twenty minutes with the tutor, right in your browser. No card, nothing to install.

Start the free trial
A session: the tutor's chat on the left, the code editor with a Java program and its output on the right