What are NullPointerExceptions?
A NullPointerException occurs when a method is called on a variable that contains null. When you make a variable hold an object, it will contain null until you actually put an object into it (such as by calling the constructor of the object type with the new keyword)
There are two parts to fixing NullPointerExceptions in your code.
- Identifying the line number that the problem occurred on, and the variable that was null and had a method called on it.
- Figuring out WHY the variable is null.
The second section will show you how to answer the first question.
And
the third section gives some various common causes of NullPointerExceptions.
Where did the NullPointerException occur?
If you already know how to determine this, then you don’t need to read this section. If you do not, then please keep reading as the first step in fixing the NullPointerException is to know what line of code it is actually occuring on!
Assume you have the following program, that uses the Flower class. It is a very boring program, it simply defines a FlowerGarden, which contains 3 flowers, and it can be told to make the flowers grow and bloom. The main method creates a new FlowerGarden and then calls growAndBloomFlowers() on it. You should put this into a file called FlowerGarden.java, and also download the
Flower.java class.
(Note that if you try and run the program, it crashes with a NullPointerException)
import ecs100.*;
public class FlowerGarden {
private Flower flower1; //Make a variable to put flower 1 in
private Flower flower2; //Make a variable to put flower 2 in
private Flower flower3; //Make a variable to put flower 3 in
public FlowerGarden() {
UI.println("New Flower Garden Created!");
}
//Make the 3 flowers grow and bloom
public void growAndBloomFlowers() {
flower1.grow(10);
flower2.grow(10);
flower3.grow(10);
flower1.bloom();
flower2.bloom();
flower3.bloom();
}
public static void main(String[] args) {
//Create a new flower garden
FlowerGarden garden = new FlowerGarden();
//Make the flowers in the garden grow and bloom
garden.growAndBloomFlowers();
}
}
Run this program. You should find that the terminal window pops up, with the following error message appearing in the terminal window.
java.lang.NullPointerException: Cannot invoke "Flower.grow(double)" because "this.flower1" is null
at FlowerGarden.growAndBloomFlowers(FlowerGarden.java:13)
at FlowerGarden.main(FlowerGarden.java:25)
This information tells us a) that it was a NullPointerException that crashed the program, and b) where the NullPointerException occurred. Look for the highest line that is referring to one of your program files. This tells you the file that the error occurred in, and the line number it occurred. In this case, we know that the error was in the FlowerGarden and occurred on line 13 and c) why it occurred ("this.flower1" is null).
We then need to go back to the code, and have a look at what is on the problematic line. In this case, it is:
flower1.grow(10);
Because NullPointerExceptions are the result of calling methods (or accessing variables on, but you don’t need to worry about this yet) on nulls, we know that “flower1” is the thing having a method called on it (the grow(...) method), so what we now need to figure out is WHY flower1 is null.
What are the possible causes for your NullPointerException?
This section assumes that you know what part of your code the exception occurred on… (read the previous section if you don’t).
For convienence, I have put the headings of the different causes here. Scroll down to find more information about each one.
- Pitfall #1 - Did you actually put objects into your object fields? Just specifying the name and type of the fields does not put objects into them!
- Common Pitfall #2 - Did you declare (i.e. specify the type of) your fields in the constructor when you were trying to set an initial value to them? If so, this code isn’t doing what you think it is!
- Common Pitfall #3 - Collections such as Arrays and ArrayLists are also objects. When you declare a collection, you are simply making a variable to hold an Array or an ArrayList or whatever collection it is you declared. Again, you need to make sure that you have actually made a new collection to put into the field. And you need to make sure you didn’t declare a local variable to put the collection in instead of putting it in the field!
- Common Pitfall #4 - Once you have declared AND initialised an Array of a set size, the slots contain nulls until you make actual objects to put into them.
- Common Pitfall #5 - When iterating over or accessing objects in a collection that might contain nulls (such as the array in the DominoGame), in order to do something to the objects, did you ensure that the object was not null before doing anything to it?
- Common Pitfall #6 - Did you check whether or not a variable is null using .equals(...)? Don't! Use ==.
- Common Pitfall #7: Not doing a null check before calling methods on a field that is allowed to be null
Common Pitfall #1
Did you actually put objects into your object fields? Just specifying the name and type of the fields does not put objects into them!
The example above on determining where a NullPointerException occurred is an example of this.
import ecs100.*;
public class FlowerGarden {
private Flower flower1; //Make a field to put flower 1 in
private Flower flower2; //Make a field to put flower 2 in
private Flower flower3; //Make a field to put flower 3 in
public FlowerGarden() {
UI.println("New Flower Garden Created!");
}
//Make the 3 flowers grow and bloom
public void growAndBloomFlowers() {
flower1.grow(10);
flower2.grow(10);
flower3.grow(10);
flower1.bloom();
flower2.bloom();
flower3.bloom();
}
public static void main(String[] args) {
//Create a new flower garden
FlowerGarden garden = new FlowerGarden();
//Make the flowers in the garden grow and bloom
garden.growAndBloomFlowers();
}
}
The NullPointerException occurs on this line.
flower1.grow(10);
Because we know that NullPointerExceptions are the result of calling methods on nulls, we know that flower1 must be a null. But why?
This code declared 3 fields of type Flower; flower1, flower2, and flower3. However, just declaring the fields does not actually put a Flower into them. In order to put a Flower into them, you need to use new Flower(...).
To correct the code, we need to make new Flowers to put into the fields in the constructor.
import ecs100.*;
public class FlowerGarden {
private Flower flower1; //Make a field to put flower 1 in
private Flower flower2; //Make a field to put flower 2 in
private Flower flower3; //Make a field to put flower 3 in
public FlowerGarden() {
flower1 = new Flower(100, 200);
flower2 = new Flower(150, 200);
flower3 = new Flower(200, 200);
UI.println("New Flower Garden Created!");
}
//Make the 3 flowers grow and bloom
public void growAndBloomFlowers() {
flower1.grow(10);
flower2.grow(10);
flower3.grow(10);
flower1.bloom();
flower2.bloom();
flower3.bloom();
}
public static void main(String[] args) {
//Create a new flower garden
FlowerGarden garden = new FlowerGarden();
//Make the flowers in the garden grow and bloom
garden.growAndBloomFlowers();
}
}
Common Pitfall #2
Did you declare (i.e. specify the type of) your fields in the constructor when you were trying to set an initial value to them? If so, this code isn’t doing what you think it is!
Consider the following code that creates a FlowerGarden which contains 3 flowers, and then tells them to grow and bloom. The flowers have been initialised in the constructor (this makes it different to the previous example), and so you might be surprised that it STILL crashes with a NullPointerException on the same line!
flower1.grow(10);
import ecs100.*;
public class FlowerGarden {
private Flower flower1; //Make a field to put flower 1 in
private Flower flower2; //Make a field to put flower 2 in
private Flower flower3; //Make a field to put flower 3 in
public FlowerGarden() {
Flower flower1 = new Flower(100, 200);
Flower flower2 = new Flower(150, 200);
Flower flower3 = new Flower(200, 200);
UI.println("New Flower Garden Created!");
}
//Make the 3 flowers grow and bloom
public void growAndBloomFlowers() {
flower1.grow(10);
flower2.grow(10);
flower3.grow(10);
flower1.bloom();
flower2.bloom();
flower3.bloom();
}
public static void main(String[] args) {
//Create a new flower garden
FlowerGarden garden = new FlowerGarden();
//Make the flowers in the garden grow and bloom
garden.growAndBloomFlowers();
}
}
The reason it crashed is because the fields actually have NOT been initialised. Instead, 3 new
local variables called flower1, flower2, and flower3 have been initialised. The fields called flower1, flower2, and flower3 do not have a value in them. So then when you tell the to grow(...) and bloom(...), you have called a method on a null.
The reason 3 new
local variables were created is because you have declared the variables, i.e. specified their type in the constructor (in this case “Flower”). When you declare a variable, you are creating a new one. If fields with the same names existed, Java doesn’t care. it simply creates some new local variables, and then any further code within that same method (in this case the constructor) will first look for local variables with the names, and then fields. If the constructor contained some code that told the flowers to grow(...), then those lines wouldn’t cause a crash as they would be accessing the local variables. But the growAndBloomFlowers(...) method wants to access the fields as it doesn’t even know about local variables that were declared inside other methods. So it crashes.
The solution is simple. Don’t declare variables when you are wanting to initialise them. The fields were already declared, they were declared above all the methods. This makes them fields. They should not (and cannot) be declared.
The correct code is as follows.
import ecs100.*;
public class FlowerGarden {
private Flower flower1; //Make a field to put flower 1 in
private Flower flower2; //Make a field to put flower 2 in
private Flower flower3; //Make a field to put flower 3 in
public FlowerGarden() {
flower1 = new Flower(100, 200);
flower2 = new Flower(150, 200);
flower3 = new Flower(200, 200);
UI.println("New Flower Garden Created!");
}
//Make the 3 flowers grow and bloom
public void growAndBloomFlowers() {
flower1.grow(10);
flower2.grow(10);
flower3.grow(10);
flower1.bloom();
flower2.bloom();
flower3.bloom();
}
public static void main(String[] args) {
//Create a new flower garden
FlowerGarden garden = new FlowerGarden();
//Make the flowers in the garden grow and bloom
garden.growAndBloomFlowers();
}
}
We have put a new flower into flower1. We do not declare it, i.e. we don’t put
Flower flower1, as this would create a local variable called flower1 and put
our new Flower there, rather than into a field. We then do the same for flower2
and flower3.
Common Pitfall #3
Collections such as Arrays and ArrayLists are also objects. When you declare a collection, you are simply making a variable to hold an Array or an ArrayList or whatever collection it is you declared. Again, you need to make sure that you have actually made a new collection to put into the field. And you need to make sure you didn’t declare a local variable to put the collection in instead of putting it in the field!
import ecs100.*;
public class FlowerGarden {
private Flower[] flowersArray; //Make a field to put a collection of flowers in
private ArrayList<Flower> flowersList;
public FlowerGarden() {
Flower[] flowersArray = new Flower[12];
ArrayList<Flower> flowersList = new ArrayList<Flower>();
for (int i=0; i<flowersArray.length; i++){
flowersArray[i] = new Flower(20*i, 200);
flowersList.add(new Flower(20*i, 400);
}
}
//Make all the flowers grow
public void growFlowers() {
for (int i=0; i<flowersArray.length; i++){
flowersArray[i].grow(10);
flowersList.get(i).grow(10);
}
...
}
growFlowers will throw a NullPointerException because there isn't an array in the flowersArray field (it's still null) and there isn't an ArrayList in the flowersList field (it's still null). Your constructor made a new array and a new list, but put them in local variables, which were then thrown away.
Solution: Whenever you put values into a field, or get a value from a field, use
this. in front of it (except for the actual field declaration):
import ecs100.*;
public class FlowerGarden {
private Flower[] flowersArray; //Make a field to put a collection of flowers in
private ArrayList<Flower> flowersList;
public FlowerGarden() {
this.flowersArray = new Flower[12];
this.flowersList = new ArrayList<Flower>();
for (int i=0; i<flowersArray.length; i++){
this.flowersArray[i] = new Flower(20*i, 200);
this.flowersList.add(new Flower(20*i, 400);
}
}
//Make all the flowers grow
public void growFlowers() {
for (int i=0; i<this.flowersArray.length; i++){
this.flowersArray[i].grow(10);
this.flowersList.get(i).grow(10);
}
...
}
Common Pitfall #4
Once you have declared AND initialised an Array of a set size, the slots contain nulls until you make actual objects to put into them.
This is not applicable to ArrayLists, as ArrayLists are not a set size. An ArrayList starts with 0 slots, and grows as objects are added to it. Whereas, an Array starts with a set number of slots, e.g. 10. Until you add objects into these slots, they initially contain nulls.
This is actually very similar to when you create a variable to hold an object of a certain type, and until you actually put an object into it, it is holding null.
When you create a new array, you are simply creating lots of slots to put objects of the desired type into. You are not actually creating the objects.
See the lecture notes if you don’t know how to put stuff into an array!
Common Pitfall #5
When iterating over or accessing objects in a collection that might contain nulls (such as the array in the DominoGame), in order to do something to the objects, did you ensure that the object was not null before doing anything to it?
Remember that until you add an object into a slot of an array, there will be a null in that slot. Alternatively, you might have deliberately set some slots back to null in order to remove the object in them. When you iterate over an array that contains null, you will be iterating over ALL slots in the array, including the nulls.
So, before you do anything to an object that you got out of an array slot, you need to ensure that it is not a null. You should do this by using ==. For example, assume you have an array that contains CartoonFigures. Not all slots in the array have a CartoonFigure (as some have been killed by setting them to null…). The slots without a CartoonFigure in them will all contain null. You want to get all the CartoonFigures to smile. If you tell a null to smile(), this will crash the program with a NullPointerException.
In order to do this you need to check that they are null before getting them out. Checking for nullness applies to any situation where an object has came out of a collection that could contain nulls.
for (CartoonFigure fig : figures) {
if (fig != null) { //If the CartoonFigure is not a null...
fig.smile();
}
}
Never use
.equals(...) to check if an object is null. If you want to know why you should never do this, check the next section.
Common Pitfall #6
Did you check whether or not a variable is null using .equals(...)?
When you are iterating over or accessing objects in a collection (such as an Array) that contains some null values, you will need to check that what you just got out of the array is not null before calling any methods on it (else you will get a NullPointerException).
Assume you have an array of CartoonFigures called figures. Some of the slots in the array contain CartoonFigures and others contain null. You would like to tell all the CartoonFigures to smile().
for (CartoonFigure fig : figures) {
if ( ! fig.equals(null)) { //If the CartoonFigure is not a null...
fig.smile();
}
}
If you did this, the code will still crash with a NullPonterException!!! Which seems very strange given that you were actually checking if the variable was null...
The crash is on this line here.
if (fig.equals(null)) {
Remember that NullPointerExceptions occur when you call null on any variable. In the cases that fig actually IS null, you have called .equals(...) on it; a method! So this causes a NullPointerException itself.
The solution is that checking if something is null should always be done with == rather than .equals. i.e. to correct the code above, we’d just say
for (CartoonFigure fig : figures) {
if (fig != null) { //If the CartoonFigure is not a null...
fig.smile();
}
}
Null checks should be done using ==. All other comparisons of objects should be done using the .equals(...) method.
If you need to see if 2 objects are equal, and there is a chance that one or both of them is null, then you will need to do 2 separate checks.
- You will need to use == to ensure that the objects are not nulls
- If they are not nulls, you will then need to use .equals(...) to see whether or not they are the same.
Common Pitfall #7
Not doing a null check before calling methods on a field that is allowed to be null.
Imagine the university has a database of students, their ID numbers, and any
special exam requirements (e.g. "needs a reader/writer, needs extra time").
- If there are no special requirements for the student, then specialRequirements
is
null. You can assume that name is NEVER null, i.e. there must
be a name.
This is the
Student
class.
public class Student{
// Fields
private String name;
private int studentID;
private String specialRequirements = null;
//Constructor: Constructs a student object with their name and student id number
public Person(String n, int id) {
this.name = name;
this.studentID = id;
}
public String getName() {
return this.name;
}
public int getID() {
return this.studentID;
}
public void addRequirement(String requirement) {
if (this.specialRequirements == null) {
//No existing requirements to avoid overwriting
this.specialRequirements = requirement;
}
else { //There are existing requirements; don't overwrite them!
this.specialRequirements += ", " + requirement;
}
}
public String getRequirements() {
return this.specialRequirements;
}
}
Disability Services has asked you to go through an array of students and to print out a list of the students who require a reader/writer, as they are currently trying to determine how many helpers they need for the upcoming exams. You know that if the special requirements contain the String "reader/writer", then that student's name should be printed. Assume the students are in an array called students (which has been populated with Student objects, some of which have requirements and others that do not).
for (int i = 0; i < students.length; i++) {
Student student = students[i]; //Get the next student
if (student.getRequirements().contains("reader/writer")) {
UI.println(student.getName());
}
}
Unless every single Student has had at least one requirement added, this code will very quickly crash with a NullPointerException on the conditional.
So, what should you do?
Firstly, you need to confirm whether it is the student that is null, or the string coming from getRequirements that is null. Split the code up such that only one method call is on each line.
for (int i = 0; i < students.length; i++) {
Student student = students[i]; //Get the next student
String requirements = student.getRequirements();
if (requirements.contains("reader/writer")) {
UI.println(student.getName());
}
}
If the code crashes on the line that is making the requirements variable, you know student is null. If it crashes at the if statement, you know that requirements is
null. Remember that NullPointerException's occur when you call a method on a null. So the thing that is having the method called on it where the NullPointerException occurred is the thing that is null.
This example is focussed on if it is requirements that is null. Remember that the student requirements is ALLOWED to be null. i.e. if the student has no requirements, the variable is null. In cases where nulls are actually allowed and valid (in many other cases, a null suggests there is a bug!), you need to be doing a null check to see whether or not the variable is null before you do anything to it.
for (int i = 0; i < students.length; i++) {
Student student = students[i]; //Get the next student
String requirements = student.getRequirements();
if (requirements != null) { //The null check
if (requirements.contains("reader/writer")) {
UI.println(student.getName());
}
}
[One other note: If you had code of this pattern, and a NullPointerException
was happening on the loop line, that would be because the
Array is null,
and it caused a NullPointerException when you accessed length on it!]