Null Pointer Exceptions in Java – One Person’s View

Java is, in my opinion, an excellent programming language for developing applications. However, when requirements are unstructured or vague, the advantages of Java become difficult to implement. Variables (or class members) that are expected to have values are sometimes found to be null (or absent of data). When a variable is found to be absent of data, a NullPointerException (NPE) is is thrown at runtime when a operation is performed to manipulate the data. The NPE is an unchecked exception, which means that the exception is only realized at runtime, not compile-time. A developer will not know that an operation will fail until the application actually executes and the variable is found to be null.
Now I made a bold comment about unstructured or vague requirements contributing to a NPE being thrown from an application. Consider the following example code:

1

2

3

4

5

6

7

publicclassPerson{

publicStringname;

publicvoidsayName(){

System.out.println(“The name is”+name.toUpperCase());

}

}

I purposely made the name variable (member) public, so the expectation is that it is easier to see how a NPE could happen in an application. There were a few assumptions made about the member name. First, that some other code will populate the member name with an actual value. Another is that when the sayName method is called, name will not be null. The code is valid in every sense of the word. It compiles without issue, and can be used within any Java application. This is the nature of unchecked exceptions. The NPE will not be seen by the compiler, but will be seen when the application is executed.

If we go back to the example code presented and review the assumptions made about the values we expect to be set, and couple these statements with what was stated about the NPE issue in Java development, we discover that it is not just inexperienced Java programmers that experience the NPE issue. It is experienced Java programmers making assumptions about how the code will be used by others in various applications.

Consider another code example:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

import java.util.List;

publicclassPeople{

privateList people;

publicList getPeople(){

returnpeople;

}

publicvoidsetPeople(List people){

this.people=people;

}

}

Again we see code that will compile without issue, but with a NPE waiting to happen. The List people is not initialized, so when we execute the following code, we get a NPE:

1

2

3

4

5

6

7

8

9

10

11

publicclassGetNpe{

publicstaticvoidmain(String[]args){

People people=newPeople();

for(Person person:people.getPeople()){

//a NullPointerException is thrown

person.sayName();

}

}

}

Once more, we compile the code without issue, only to encounter a NPE at runtime.

This issue, to me, is not an issue of inexperience, but miscommunication. The programmer writing the code we have seen made assumptions that were not shared or documented about the usage of the code. Additionally, some basics about the language were neglected in favor of a particular usage of the code. In other words, the person who wrote the code we have seen should have thought about defensive coding and questioned some of the assumptions made about the code’s usage. Will the name always have a value, and if not, can it be empty? Is there a reason why the List of People cannot be initialized to an empty List?

I have listed several references at the end of this article with the best practices offered by others in Java development. In the end, making sure that instances of NPEs in an application can be reduced (or even eliminated to a greater or lesser extent) by making sure that all variables have some type of value (initialized).

If we modify our original code in the following ways, we avoid throwing a NPE:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

publicclassPerson{

// initialize name to a String, with no value

publicStringname=newString();

publicvoidsayName(){

System.out.println(“The name is”+name.toUpperCase());

}

}

//----------

import java.util.ArrayList;

import java.util.List;

publicclassPeople{

// initialize the List of people to a new ArrayList

privateList people=newArrayList();

publicList getPeople(){

returnpeople;

}

publicvoidsetPeople(List people){

this.people=people;

}

}

//----------

publicclassGetNpe{

publicstaticvoidmain(String[]args){

People people=newPeople();

for(Person person:people.getPeople()){

//NO NullPointerException is thrown now

person.sayName();

}

}

}

Now when we execute the GetNpe application, we get nothing returned on the command line, but no NPE. This may or may not be what is expected, but now we can see that there is an absence of data versus a NPE. We know when name has no value, or there is no List of people, then nothing is returned when the GepNpe application is executed. We can now question why there are no names or people to see when GetNpe is executed.

I personally do not see the need to initialize every variable, but checking for a NPE where it is necessary is a matter of understanding what may be null when the application is executed. There are fancy ways to insulate one’s self from NPEs, but I believe the easiest way is to understand the requirements of the application, how others understand the application’s requirements, and the data being manipulated by the application.