How to prevent NullPointerExceptions in Java
Tags: codesecurity, java
Published: 2023-09-22 02:00:21

As an experienced Java developer, you're likely familiar with the intricacies of Java exceptions. These events signal abnormal conditions during program execution and, when not handled properly, can disrupt the normal flow of your application, leading to crashes or unexpected behavior.


Among the various Java exceptions, you need to pay special attention to `NullPointerExceptions`. These exceptions are particularly notorious, as they tend to be a common source of runtime errors and can significantly impact your application's stability and reliability.


In this article, you'll learn all about `NullPointerExceptions` in Java, including their causes, consequences, and most importantly, prevention techniques.


Why you should avoid NullPointerExceptions
------------------------------------------


A `NullPointerException` represents a runtime anomaly in Java that occurs when someone tries to access or modify an object reference possessing a `null` value. This `null` reference signifies the absence or non-instantiation of the object in question. When the Java virtual machine (JVM) finds a `null` reference during object manipulation, it generates a `NullPointerException`. Understanding and addressing the causes of these exceptions can help in developing stronger and more robust applications.


`NullPointerExceptions` can occur in various situations, including the following:


* When accessing an instance variable or invoking a method on a `null` object.
* When accessing an element in an array or a collection with a `null` reference.
* When unboxing a `null` reference from a wrapper object to its corresponding primitive type.
* When passing a `null` reference as an argument to a method that doesn't expect it.


These situations typically result from programming errors, such as failing to initialize an object, mishandling `null` values, or not properly checking for `null` values before performing operations on objects. 


Unfortunately, `NullPointerExceptions` can have numerous negative consequences in a development environment, including the following:



* **Application crashes:** When a `NullPointerException` occurs, it often leads to an abrupt termination of the application, causing user dissatisfaction and potential loss of unsaved data.
* **Unpredictable behavior:** `NullPointerExceptions` can lead to unpredictable application behavior, making it difficult to reproduce and diagnose issues.
* **Debugging challenges:** Tracking down the root cause of a `NullPointerException` can be time-consuming and complicated, especially in large and complex codebases.
* **Security vulnerabilities:** In some cases, `NullPointerExceptions` may expose security vulnerabilities, as they can be exploited by malicious users to bypass certain checks or gain unauthorized access to sensitive data.
* **Decreased developer productivity:** Frequent `NullPointerException` may hinder productivity, as developers need to spend additional time fixing and testing these issues.


Fortunately, when you understand the causes, consequences, and prevention techniques for `NullPointerExceptions`, you can minimize their occurrence and create more stable, more efficient, and more secure Java applications.


How to prevent NullPointerExceptions in Java
--------------------------------------------


To prevent `NullPointerExceptions` in Java, developers can employ a variety of techniques and best practices, including using the ternary operator and the [Apache Commons StringUtils library](https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html).


### Use the ternary operator


Instead of using an if-else statement, you can use the [ternary operator](https://www.javatpoint.com/ternary-operator-in-java) to check for `null` values and provide a default value, reducing the risk of `NullPointerExceptions`. The ternary operator is better for concise and readable conditional statements that handle `null` values and provide default values in Java:



```
String input = null;
String result = (input != null) ? input : "default";
```

This code assigns the value `default` to the variable `result` if the variable `input` is `null`. If it's not `null`, it assigns the value of `input` to `result`. It uses the ternary operator to check for `null` values and provide a default value.


### Use `StringUtils` from Apache Commons


The Apache Commons StringUtils library provides utility methods to safely handle `null` values in strings, reducing the risk of `NullPointerException`. This prevents unexpected application crashes or security vulnerabilities that can arise from `null` values:



```
import org.apache.commons.lang3.StringUtils;
String input = null;
boolean isBlank = StringUtils.isBlank(input); // Returns true if null, empty, or whitespace
```

This code uses the `StringUtils` class from the `org.apache.commons.lang3` package to check if a string is `null`, is empty, or contains only whitespace characters, and assigns the result to the `isBlank` Boolean variable.


You can minimize potential security risks from third-party libraries like Apache Commons StringUtils by using [Snyk to scan for Java vulnerabilities](https://docs.snyk.io/guides/snyk-for-java-developers). In addition, using the latest version of third-party libraries is crucial for security and stability. For Apache Commons StringUtils, check the latest version on their [official website](https://commons.apache.org/proper/commons-lang/) and update accordingly in your project's `pom.xml`.


### Use primitives over objects


Whenever possible, you should use primitive types instead of their corresponding wrapper classes to avoid potential `null` values, which cannot be `null`. Unfortunately, their corresponding wrapper classes can be `null`, leading to the possibility of a `NullPointerException` if they are not properly handled:



```
int primitiveInt = 0; // A primitive int cannot be null
Integer objectInt = null; // An Integer object can be null, leading to a NullPointerException
```

This code declares an integer variable `primitiveInt` with a value of `0`, which is primitive (and therefore, cannot be `null`), as well as an `objectInt` variable of the `Integer` class, which can be `null` and can potentially lead to a `NullPointerException` if not handled properly.


### Avoid returning `null` in methods


Instead of returning `null` values from methods, return an empty object:



```
public List getStrings() {
 return Collections.emptyList(); // Return an empty list instead of null
}
```

This code defines a method `getStrings()` that returns an empty list of strings using the `Collections.emptyList()` method instead of returning a `null` value. This approach is preferred because it avoids potential `NullPointerExceptions` and promotes consistency in the handling of return values, making the code easier to read and maintain. A valuable approach to prevent returning `null` from Java methods involves the use of `Optional`. We will delve deeper into this concept later in our discussion.


### Use `.equals()` safely


Use `.equals()` on a known non-null object, or use `Objects.equals()` to avoid `NullPointerExceptions` when comparing objects:



```
String str1 = "hello";
String str2 = null;
// Safe usage of .equals()
boolean isEqual = str1.equals(str2); // Returns false, no NullPointerException
// Using Objects.equals()
boolean isEqualObjects = Objects.equals(str1, str2); // Returns false, no NullPointerException
```

This code declares two string variables: `str1` and `str2`. It uses the `.equals()` method on the non-null `str1` object and `Objects.equals()` to compare `str1` and `str2` safely by checking for `null` values to avoid potential `NullPointerExceptions` when comparing objects.


### Prevent passing `null` as a method argument


Use annotations like `@NotNull` to indicate that a method should not accept `null` arguments, enabling compile-time checks:



```
public void doSomething(@NotNull String input) {
    // Method implementation
}
```

### Use the `@NonNull` annotation from Lombok


[Lombok](https://projectlombok.org/) is a widely used library that simplifies Java code. The `@NonNull` annotation helps enforce non-null parameters, generating appropriate `null` checks:



```
import lombok.NonNull;
public void doSomething(@NonNull String input) {
    // Method implementation
}
```

This code imports the `@NonNull` annotation from the Lombok library and uses it to specify that the `input` parameter of the `doSomething` method must not be `null`. This helps prevent potential `NullPointerExceptions` by checking for `null` values at compile time.


### Use `null` object pattern


The `null` object pattern is a design pattern that provides a default object in place of `null` values, reducing the risk of `NullPointerExceptions`:



```
public interface Animal {
    void makeSound();
}
public class Dog implements Animal {
    @Override
    public void makeSound() {
        System.out.println("Woof!");
    }
}
public class NullAnimal implements Animal {
    @Override
    public void makeSound() {
        // Do nothing
    }
}
public class AnimalFactory {
    public Animal getAnimal(String type) {
        if ("Dog".equalsIgnoreCase(type)) {
            return new Dog();
        }
        return new NullAnimal();
    }
}
```

This code defines an `Animal` interface and two classes that implement the interface: `Dog` and `NullAnimal`. The `AnimalFactory` class contains a method, `getAnimal()`, that takes a `String` argument and returns an instance of `Dog` or `NullAnimal` depending on the argument.


This approach is useful for handling `null` values because it allows for the creation of a default `NullAnimal` object in case an invalid or `null` argument is passed to `getAnimal()`. This can prevent potential `NullPointerExceptions` and ensure consistent behavior in the program.


### Use the Java Stream API to handle `null` values in collections


The [Java Stream API](https://www.javatpoint.com/java-8-stream) provides methods to handle `null` values in collections safely:



```
List strings = Arrays.asList("Hello", null, "World");
strings = strings.stream().filter(Objects::nonNull).collect(Collectors.toList());
```

This code uses a stream to filter out `null` elements from a list of strings, preventing potential `NullPointerExceptions` that may occur when trying to access `null` values in the list.


This approach simplifies `null` checking and helps to prevent unexpected application crashes or security vulnerabilities that may arise from `null` values in collections.


### Validate method arguments with a dedicated utility method


Create a utility method to validate arguments and throw a custom exception when `null` values are encountered. This can be helpful in enforcing non-null requirements in method parameters:



```
public static  T checkNotNull(T reference, String errorMessage) {
 if (reference == null) {
 throw new IllegalArgumentException(errorMessage);
 }
 return reference;
}
public void doSomething(String input) {
 input = checkNotNull(input, "Input should not be null");
 // Method implementation
}
```

This code defines a `checkNotNull` method that throws an `IllegalArgumentException` if the `reference` parameter is `null` and a `doSomething` method that uses the `checkNotNull` method to ensure that the `input` parameter is not `null` before proceeding with the method implementation.


This approach is important for preventing potential `NullPointerExceptions` by checking for `null` values at runtime and throwing an exception if `null` values are encountered.


### Use default methods in interfaces


When using interfaces, provide default methods to handle potential `null` objects, thus avoiding `NullPointerExceptions`:



```
public interface Processor {
    default void process(String input) {
        if (input == null) {
            handleNullInput();
        } else {
            doProcess(input);
        }
    }

    void doProcess(String input);

    default void handleNullInput() {
        // Handle null input or throw a custom exception
    }
}
public class MyProcessor implements Processor {
	@Override
	public void doProcess(String input) {
		System.out.println("Processing input: " + input);
	}
	// optionally override the handleNullInput method
	@Override
	public void handleNullInput() {
		System.out.println("Null input encountered.");
	}
}
```

This code defines an interface `Processor` with a default `process()` method that checks for `null` input values and calls either `doProcess()` or `handleNullInput()`. The `PMyProcessor` class implements the `Processor` interface and overrides the `doProcess()` and `handleNullInput()` methods to define custom behavior.


This approach helps to prevent potential `NullPointerExceptions` by providing a consistent way to handle `null` input values, allowing for the implementation of custom behavior or exception handling when `null` values are encountered.


### Use the Builder pattern


The [Builder pattern](https://www.javatpoint.com/builder-design-pattern) can help you create complex objects with optional parameters (including things like color, size, shape, or other customizable features of an object), ensuring that required parameters are always set and non-null:



```
public class Person {
    private final String firstName;
    private final String lastName;

    private Person(Builder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
    }

    public static class Builder {
        private final String firstName;
        private String lastName = "";

        public Builder(String firstName) {
            this.firstName = Objects.requireNonNull(firstName, "First name must not be null");
        }

        public Builder lastName(String lastName) {
            this.lastName = Objects.requireNonNull(lastName, "Last name must not be null");
            return this;
        }

        public Person build() {
            return new Person(this);
        }
    }
}
```

This code defines a `Person` class with a private constructor that only accepts a `Builder` object, which contains two fields: `firstName` and `lastName`. The `Builder` class ensures that the `firstName` field is not `null` by using `Objects.requireNonNull()` to check it at construction time, while the `lastName` field is allowed to be `null` but must be checked and set using the `lastName()` method.


This approach helps to prevent potential `NullPointerExceptions` by ensuring that all required fields are initialized and checked for `null` values at construction time. This promotes both consistency and reliability in the program.


### Use the double-checked locking pattern with the `singleton` pattern


When creating `singletons`, the [double-checked locking pattern](https://en.wikipedia.org/wiki/Double-checked_locking) can help ensure that the `singleton` instance is never `null`:



```
public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
```

This code defines a `Singleton` class that ensures only one instance of the class is created at runtime and uses double-checked locking to prevent potential race conditions and `NullPointerExceptions`.


This approach is important for preventing `NullPointerExceptions` because it ensures that the instance of the `Singleton` class is only created once and that subsequent calls to the `getInstance()` method return the same instance. This helps to prevent `null` values from being accidentally assigned to the `instance` variable and causing potential `NullPointerExceptions`.


### Use the Optional class


The [Optional class](https://www.javatpoint.com/java-8-optional) is a powerful tool to avoid `NullPointerExceptions` by explicitly handling potential `null` values:



```
import java.util.Optional;
public class OptionalExample {
    private String someString;
    public OptionalExample(String someString) {
        this.someString = someString;
    }
    public Optional getString() {
 return Optional.ofNullable(someString);
 }
}
//Usage
OptionalExample example1 = new OptionalExample("Hello, World!");
Optional optString1 = example1.getString();
String value1 = optString1.orElse("default");
System.out.println(value1); // Output: Hello, World!
OptionalExample example2 = new OptionalExample(null);
Optional optString2 = example2.getString();
String value2 = optString2.orElse("default");
System.out.println(value2); // Output: default
```

This code uses the `Optional` class to handle `null` values, explicitly indicating that a value may be absent and using `orElse()` to provide a default value, thus, preventing potential `NullPointerExceptions`. It's important not to call `get()` directly on `Optional`. Instead, methods like `orElse()` are used to provide a default value when the `Optional` is empty, thus preventing `NoSuchElementException`. 


This approach not only makes it clear that a value may or may not be present, but also enforces the correct handling of these cases, helping to avoid potential errors like `NullPointerException` or `NoSuchElementException`.


### Test often and test early


Make sure you write comprehensive unit tests to catch `NullPointerExceptions` during development before they cause issues in production:



```
@Test
public void testGetStrings() {
    MyClass obj = new MyClass();
    List result = obj.getStrings();
 assertNotNull(result); // Ensure the result is not null
}
```

This code defines a [JUnit](https://junit.org/junit5/) test case for the `getStrings()` method of the `MyClass` class. Then it creates an instance of `MyClass`, calls the `getStrings()` method, and asserts that the result is not `null` using the `assertNotNull()` method.


This approach is useful in preventing potential `NullPointerExceptions` by verifying that the result of the `getStrings()` method is `not null` before performing any subsequent operations on it. By ensuring that the result is `not null`, the test case can help to identify any potential issues with `null`values and prevent unexpected application crashes or security vulnerabilities.


NullPointConclusion
-------------------


Preventing `NullPointerExceptions` in Java applications is crucial for creating robust, reliable, and secure software. From Java 14 onwards, there have been enhancements for better [NullPointerException handling](https://openjdk.org/jeps/358), making it easier to prevent and troubleshoot these exceptions. This means that updating to newer Java versions can be beneficial for debugging purposes.


By employing a combination of techniques, such as using the ternary operator, validating method arguments, and adopting design patterns, like the Builder and null object patterns, you can effectively mitigate the risk of encountering `NullPointerExceptions`. Incorporating these practices not only helps improve the application's stability but enhances the overall development experience.


Snyk is an essential tool for developers looking to create secure and reliable applications. With Snyk, you have access to a range of tools and services designed to detect and fix security vulnerabilities in your code. Snyk also offers integration with popular development environments and platforms, making it easy to incorporate security into your development process.


To take your Java development experience to the next level and contribute to the security and stability of the software ecosystem, you should consider using some of Snyk's powerful tools, including Snyk's [IDE plugins](/platform/ide-plugins/), [CLI](/platform/snyk-cli/), and [free, hands-on Java security lessons](https://learn.snyk.io/lessons/java/). These tools can help you detect and report security vulnerabilities, including `NullPointerExceptions`, ensuring your applications are secure and reliable.