Dev Learning Lab

The labs on this site need JavaScript to run. The same content is written out below.

Fundamentals › Java

null

What is null, and why does NullPointerException happen?

The variable name does not hold an object such as a string itself. It holds a value that refers to that object (a reference). null is a special value that you store in this place to say "refers to no object," and in code you write it like String name = null;. In name.length(), the dot (.) means "ask the object that name refers to," but if name is null there is no object to ask, so an exception called NullPointerException is thrown. if (name != null) is a check that first asks whether name refers to an object. The empty string "", which has no characters at all, is not null. It is a string object with 0 characters. In this lab you change the value stored in name to "kim", null, or "", and you add or remove the if check. The same code is compiled and run, and you see what is printed and whether an exception is thrown.

Checked against real execution · Compiled 6 combinations with javax.tools on JDK 21, ran them as java processes, and checked the results

Concepts in this lab

null
null is a value that shows that a variable refers to no object. In the Java language specification, the type of the null literal (the null you write in code) is the null type, which has no name, and the only value of that type is the null reference. You can store null in a variable of any reference type, so you can write String name = null;, and then the name variable has been created but refers to no object. So if you put a dot (.) after a null variable to call a method of an object, there is nothing to ask, and a NullPointerException is thrown. null is different from the empty string "", which has 0 characters. "" is an object that exists but has no characters, and null is no object at all.
NullPointerException
This exception is thrown when code tries to call a method or read a field through a reference that is null. null means that there is no object that the reference refers to, and an object that does not exist cannot be asked to do anything, so the exception is thrown. Whether a value is null depends on the values at run time, so the compiler cannot catch it in advance and it shows up only when the code runs (it is an unchecked exception, so handling is not forced either). This exception is also thrown when null is passed to a method that is written not to accept null (such as Optional.of or Objects.requireNonNull). In places where a value may be absent, you make this exception less likely by checking for null first or by using Optional to show in the type that the value may be absent.
Checking for null
Checking for null is code that checks, before you use a variable, whether the variable is not null, as in if (name != null). When you compare references with !=, the result is false if both are null or both refer to the same object, and true otherwise, so name != null is true when name refers to some object. An if statement runs the first block when the condition is true and the else block when it is false, so if you put a call such as name.length() only in the true block, that call does not run when name is null. name != null asks only whether an object exists, not whether it has characters, so the empty string "" passes this check.
Empty string
The empty string is a string with no characters at all, and in code you write it as two double quotation marks together, "". A string literal is, at run time, a value that refers to a String object, so "" is also not null but a String object whose length is 0. Calling length() on this object returns 0 and throws no exception, and isEmpty() returns true when length() is 0. You need to tell it apart from null because you can call methods on an empty string since the object exists, but calling a method on null throws a NullPointerException.

Try these

Running with the default settings

  1. The line String name = "kim"; runs. name is a variable, and a variable holds not the object itself but a value that refers to the object (a reference). Here name comes to refer to a String object that holds the characters "kim". That object is the box on the right.
  2. At the line System.out.println(name.length());, name.length() is evaluated first. The dot (.) means "ask the object that name refers to," and length() is a request to count the characters. The "kim" object counts its characters and returns 3.
  3. The returned 3 is passed to println.
  4. System.out.println prints 3.
  5. The last line of main runs and the program ends. No exception was thrown.

Result of this run

Code

public class Main {
    public static void main(String[] args) {
        // Variable: refers to a string object, or to nothing if it is null
        String name = "kim";
        System.out.println(name.length());
    }
}

Assumptions of this model

The compiler and runtime are JDK 21.0.12.1 (javac 21, java 21). All 6 combinations were checked against real runs: the same source as the code on the screen (identical line by line) was compiled with javax.tools, and the compiled Main was run in a new java process, and the standard output, the first line of the standard error, and the exit code were captured. What was checked is whether compilation succeeded, the output, whether an exception was thrown (whether the first line of the standard error is NullPointerException) and the line where it was thrown (the line the stack trace pointed to is the name.length() line), and the exit code. The "length() runs" column of the table was worked out from the real output by whether a character count appeared in it, and the "if check" column by which block's output appeared. The facts that the step sentences rely on were checked with a separate program. For each of the three values: name == null is false for "kim", true for null, and false for ""; length() is 3, (cannot be called because it is null), and 0; and the line String name = null; runs without an exception, the exception is thrown at the next line, name.length(), and the program ends with exit code 1. I opened the documentation myself. That the null type has only one value, the null reference, and that it can be stored in any reference type follows sections 3.10.8 and 4.1 of the Java Language Specification (Java SE 21); that a reference value either refers to an object or is the null reference that refers to no object follows section 4.3.1; the rules for comparing references with == and != follow section 15.21.3; that an if statement runs the first statement when the condition is true and the else statement when it is false follows sections 14.9.1 and 14.9.2; and that a string literal is, at run time, a value that refers to a String object, and that "" is the empty string, follows section 3.10.5. The NullPointerException API documentation says that it is thrown when an instance method of a null object is called (Java SE 21 API), and I also opened the descriptions of String.length() and isEmpty() in the same API documentation. The sentence that a NullPointerException is thrown when the target of an instance method call is null I confirmed in chapter 15 (section 15.6) of the JLS, but I could not open the text of sections 15.12.4.1 and 15.12.4.4, which specify the call handling in detail. The javac on the PC used to write this lab does not put variable names in the class file, so the detail message of the NullPointerException showed <local1> instead of name. This message is not specified by the specification but was observed on this JDK, so it is not used on the screen. The code on the screen is exactly the shape that really compiles, and nothing was shortened. Beyond that, primitive variables such as int and null, arrays or fields that are null at first, comparing two strings with == and equals, and how to handle a value that may be null with Optional are not covered. Optional is covered in the in-depth lab "Optional".

Previous lab: References · Next lab: Constructors

Concepts in this lab

What this lab shows

Settings

Code


      
    

Diagram

Run comparison

Try these