Your first class compiles without a single complaint. You run it, and instead of the account you expected, Java prints this:
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:
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 calltoUpperCase()on aString.because "this.owner" is null: which value was missing. The fieldownerof this object wasnull.
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:
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":
public Account(String owner) {
this.owner = owner;
}ALEX: 0.0Four 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:
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());
}
}
}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:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "name" is nullFill 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:
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);
}
}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:
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));No score for Robin
Robin: 04. Comparing a string that might be null
String answer = null;
if (answer.equals("yes")) {
System.out.println("OK");
}Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because "<local1>" is nullTurn 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
- Read the first line: what Java tried to do (
Cannot invoke "...") and which value was null (because "..." is null). - Go to the top
atline in your own code and find that value on that line. - Ask where that value should have been set: a constructor, an array slot, a
getcall, a method that returns something. That's where the real bug is, usually a few lines earlier. - Fix it there: set the field (with
this.), fill the array, handle the missing key, or put the known value first inequals.
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?
