In Java, a special null value can be assigned to an object’s reference and denotes
that the object is currently pointing to unknown piece of data. A NullPointerException is thrown when an application is trying to use or access an
object whose reference equals to null. The following cases throw that exception:
- Invoking a method from a null object.
- Accessing or modifying a null object’s field.
- Taking the length of null, as if it were an array.
- Accessing or modifying the slots of null object, as if it were an array.
- Throwing null, as if it were a Throwable value.
- When you try to synchronize over a null object.
The NullPointerException is a RuntimeException and thus, the Javac compiler does not force you to use a try-catch block
to handle it appropriately.
Why
do we need the null value?
As already mentioned, null is a special value used in Java. It is extremely useful in
coding some design patterns, such as Null Object pattern and Singleton pattern. The Null Object pattern
provides an object as a surrogate for the lack of an object of a given type.
The Singleton pattern ensures that only one instance of a class is created and
also, aims for providing a global point of access to the object.
For example, a sample way to create at
most one instance of a class is to declare all its constructors as private
and then, create a public method that returns the unique instance of the class:
TestSingleton.java:
import java.util.UUID;
|
||
|
class Singleton {
|
||
|
private static Singleton single =
null;
|
||
private String ID = null;
|
|
||
private Singleton() {
|
/*
Make it private, in order to prevent the creation of new instances of
|
||
*
the Singleton class. */
|
|
||
ID
= UUID.randomUUID().toString(); // Create a random ID.
|
}
|
||
|
public static Singleton
getInstance() {
|
||
if (single == null)
|
single
= new Singleton();
|
||
|
return single;
|
||
}
|
|
||
public String getID() {
|
return this.ID;
|
||
}
|
}
|
||
|
public class TestSingleton {
|
||
public static void main(String[] args)
{
|
Singleton
s = Singleton.getInstance();
|
||
System.out.println(s.getID());
|
}
|
||
}
|
In this example, we declare a static
instance of the Singleton class. That instance is initialized at most once
inside the getInstance method. Notice the use of the null value that enables the unique instance creation.
How
to avoid the NullPointerException
In order to avoid the NullPointerException, ensure that all your objects are initialized properly,
before you use them. Notice that, when you declare a reference variable, you
are really creating a pointer to an object. You must verify that the pointer is
not null, before you request the method or a field from the object.
Also, if the exception is thrown,
use the information residing in the exception’s stack trace. The execution’s
stack trace is provided by the JVM, in order to enable the debugging of the
application. Locate the method and the line where the exception was caught and
then, figure out which reference equals to null in that specific line.
In the rest of this section, we will
describe some techniques that deal with the aforementioned exception. However,
they do not eliminate the problem and the programmer should always be careful
while coding an application.
1.
String comparison with literals
A very common case in an
application’s execution code involves the comparison between a String variable
and a literal. The literal may be a String or the element of an Enum. Instead
of invoking the method from the null object, consider invoking it from the
literal. For example, observe the following case:
String
str = null;
|
||
if(str.equals("Test"))
{
|
/*
The code here will not be reached, as an exception will be thrown. */
|
||
}
|
The above code snippet will throw a NullPointerException. However, if we invoke the method from the literal, the
execution flow continues normally:
String
str = null;
|
||
if("Test".equals(str))
{
|
/*
Correct use case. No exception will be thrown. */
|
||
}
|
2.
Check the arguments of a method
Before executing the body of your
own method, be sure to check its arguments for null values. Continue with the
execution of the method, only when the arguments are properly checked.
Otherwise, you can throw an IllegalArgumentException and notify the calling method that something is wrong with
the passed arguments.
For example:
public static int getLength(String s)
{
|
||
if (s == null)
|
throw new IllegalArgumentException("The
argument cannot be null");
|
||
|
return s.length();
|
||
}
|
3.
Prefer String.valueOf() method instead of toString()
When your application’s code
requires the String representation of an object, avoid using the object’s toString method. If your object’s reference equals to null, a NullPointerException will be thrown.
Instead, consider using the static String.valueOf
method, which does not throw any exceptions and prints "null", in case the function’s argument equals to null.
4.
Use the Ternary Operator
The ternary operator can be very useful and can help us avoid the NullPointerException. The operator has the form:
boolean expression ? value1 : value2;
|
First, the boolean expression is
evaluated. If the expression is true then, the value1 is returned, otherwise,
the value2 is returned. We can use the ternary operator for handling null pointers as follows:
String message = (str == null) ? "" : str.substring(0, 10);
|
The message variable will be empty
if str’s reference is null. Otherwise, if str points to actual data, the message will retrieve the first
10 characters of it.
5.
Create methods that return empty collections instead of null
A very good technique is to create
methods that return an empty collection, instead of a null value. Your application’s code can iterate over the empty
collection and use its methods and fields, without throwing a NullPointerException. For example:
Example.java
public class Example {
|
||
private static List<Integer>
numbers = null;
|
|
||
public static List<Integer>
getList() {
|
if (numbers == null)
|
||
return Collections.emptyList();
|
else
|
||
return numbers;
|
}
|
||
}
|
6.
Make use of Apache’s StringUtils class
Apache’s Commons Lang
is a library that provides helper utilities for the java.lang API, such as String manipulation methods. A sample class
that provides String manipulation is StringUtils.java, which handles null input Strings quietly.
You can make use of the StringUtils.isNotEmpty, StringUtils.IsEmpty and StringUtils.equals methods, in order to avoid the NullPointerException. For example:
if (StringUtils.isNotEmpty(str))
{
|
||
System.out.println(str.toString());
|
}
|
7.
Use the contains(), containsKey(), containsValue() methods
If your application code makes use
of collections, such as Maps,
consider using the contains, containsKey and containsValue methods. For example, retrieve the value of a specific key,
after you have verified its existence in the map:
Map<String,
String> map = …
|
||
…
|
String
key = …
|
||
String
value = map.get(key);
|
System.out.println(value.toString());
// An exception will be thrown, if the value is null.
|
In the above snippet, we don’t check
if the key actually exists inside the Map and thus, the returned value can be null. The safest way is the following:
Map<String,
String> map = …
|
||
…
|
String
key = …
|
||
if(map.containsKey(key))
{
|
String
value = map.get(key);
|
||
System.out.println(value.toString());
// No exception will be thrown.
|
}
|
8.
Check the return value of external methods
It is very common in practice to
make use of external libraries. These libraries contain methods that return a
reference. Make sure that the returned reference is not null. Also, consider reading the Javadoc of the method, in order
to better understand its functionality and its return values.
9.
Use Assertions
Assertions are very useful while
testing your code and can be used, in order to avoid executing code snippets
that will throw a NullPointerException. Java Assertions are implemented with the assert keyword
and throw an AssertionError.
Notice that you must explicitly
enable the assertion flag of the JVM, by executing it with the –ea argument. Otherwise, the assertions will be completely
ignored.
A sample example using Java
assertions is the following:
public static int getLength(String s)
{
|
||
/*
Ensure that the String is not null. */
|
assert (s != null);
|
||
|
return s.length();
|
||
}
|
If you execute the above code
snippet and pass a null argument to getLength, the following error message will appear:
Exception
in thread "main" java.lang.AssertionError
|
10.
Unit Tests
Unit tests can be extremely useful
while testing the functionality and correctness of your code. Devote some time
to write a couple tests cases that verify that no NullPointerException is thrown, while your application’s code undergoes a
specific execution flow.
Existing
NullPointerException safe methods
1.
Accessing static members or methods of a class
When your code attempts to access a
static variable or method of a class, even if the object’s reference equals to null, the JVM does not throw a NullPointerException. This is due to the fact that the Java compiler stores the
static methods and fields in a special place, during the compilation procedure.
Thus, the static fields and methods are not associated with objects, rather
with the name of the class.
TestStatic.java:
class SampleClass {
|
||
public static void printMessage() {
|
||
System.out.println("Hello
from Java Code Geeks!");
|
}
|
||
}
|
|
||
public class TestStatic {
|
public static void main(String[] args)
{
|
||
SampleClass
sc = null;
|
sc.printMessage();
|
||
}
|
}
|
Notice, that despite the fact that
the instance of the SampleClass equals to null, the method will be executed properly. However, when it
comes to static methods or fields, it is better to access them in a static way,
such as SampleClass.printMessage().
2.
The instanceof operator
The instanceof operator can be used, even if the object’s reference equals
to null. The instanceof operator returns false when the reference equals to null
and does not throw a NullPointerException. For example consider the following code snippet:
String
str = null;
|
||
if(str
instanceof String)
|
System.out.println("It's
an instance of the String class!");
|
||
else
|
System.out.println("Not
an instance of the String class!");
|
The result of the execution is, as
expected:
No comments:
Post a Comment