Home Null in Java: A Bad Invention.
Post
Cancel

Null in Java: A Bad Invention.

In the programming field, there are a lot of wrong inventions. Null References is one of them. Java introduced this invention in the initial version, which led many developers to develop the bad habit of using null mindlessly. Although Optional was used to replace Null after Java 8, the bad habit of using Null cannot be replaced.

“I call it my billion-dollar mistake. It was the invention of the Null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object-oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

— Tony Hoare (Turing Award winner)


Contents


What is Null in Java?

In Java, Null is a special value that can be assigned to object references. It represents the absence of an object or a default value.

It is neither an object nor a type, which is a common misconception that newcomers to the Java language must overcome.

Why Null is A Bad Invention?

Null as a “bad invention” in Java, and indeed in many other programming languages, is a perspective shared by many software engineers and computer scientists, most notably Tony Hoare, who invented the null reference. Hoare himself has referred to the invention of the Null reference as his “billion-dollar mistake”.

It has the following drawbacks:

  1. Null Pointer Exceptions: One of the most common causes of runtime errors in Java is the NullPointerException. This occurs when a program attempts to use an object reference that has been assigned null. Such errors can lead to system crashes and are often only discovered during runtime. Any lack of null pointer checking can make programs out of control.

  2. Reliability: The presence of null can make software less reliable. Since any reference can potentially be Null, developers must constantly check for null to avoid exceptions, which adds verbosity and complexity to the code.

  3. Ambiguity: Null can sometimes represent multiple meanings, such as uninitialized, absence of a value, or an error condition. This ambiguity can lead to confusion and errors in understanding code. In most cases, the caller has no idea about the intention of the method to return Null.

In Java, due to the existence of Null:

  • our programs often crash because of unpredictable NullPointerException;
  • our code is filled with lots of meaningless null checks;
  • we are often confused by the Null return from methods.

“When we return null, we are essentially creating work for ourselves and foisting problems upon our callers. All it takes is one missing null check to send an application spinning out of control.”

— Robert C. Martin

Try to Avoid Using Null

Modern programming languages and updates to existing languages have introduced features to mitigate the problems caused by Null. For example, Java 8 introduced Optional to represent the presence or absence of a value.

In Java, instead of returning Null, we can throw an exception or return Optional:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Returning null (not recommended)
public User findUser(String userId) {
  //...
  return null;
}

// Throwing an exception (using for error condition)
public User findUser(String userId) {
   //...
   throw new UserNotFoundException("User not found with ID: " + userId);
}

// Returning an optional (using for absence of the value)
public Optional<User> findUser(String userId) {
  //...
  return Optional.empty();
}

Example of Using Optional to replace Null

I can provide a simpler example to show the difference between Optional and Null.

Suppose we have a method that tries to retrieve a user’s email address from a database, but there is a chance that the corresponding user will not be found.


Example of Null:

1
2
3
4
5
6
7
8
public String getEmailOfUser(String userId) {
    User user = findUser(userId); // This method might return null
    if (user != null) {
        return user.getEmail();
    } else {
        return "Email not found";
    }
}

Example of Optional:

1
2
3
4
public String getEmailOfUser(String userId) {
    Optional<User> user = findUser(userId);
    return user.map(User::getEmail).orElse("Email not found");
}

The advantage of Optional:

  • Code Conciseness: In the Optional example, we avoid the traditional if-else structure, making the code more concise and readable. We also avoid redundant null checks.
  • Null Safety: By using Optional, we can handle potential null values more safely. We reduce the risk of NullPointerException, which can make programs out of control.
  • Functional Style: The use of Optional supports a functional programming approach, making the code style more modern and fluent.

If a method needs to return empty values, use Optional. This can avoid NullPointerException and meaningless null checking. It also reminds the caller that there may be empty values here.

Please don’t use Null unless you have strong reasons for it.

When I worked at Huawei, colleagues in my group didn’t follow this rule very well. This leads to our project crashing often due to null pointers, and the error logs were full of NullPointerExceptions.

And every time I did code review, my colleagues would always remind me if I did null-pointer checking on the variables. It was really annoying and time-wasting.

So, please don’t use Null.

This post is licensed under CC BY 4.0 by the author.
ip