How do I test null and non-null values in JUnit?

To test null and non-null values in JUnit, use these assertions:

  • assertNull(value) — passes if the value is null
  • assertNotNull(value) — passes if the value is not null

In JUnit 5, these methods are available from org.junit.jupiter.api.Assertions.

Basic Example

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertNotNull;

class NullCheckTest {

    @Test
    void valueShouldBeNull() {
        String name = null;

        assertNull(name);
    }

    @Test
    void valueShouldNotBeNull() {
        String name = "John";

        assertNotNull(name);
    }
}

Using Assertion Messages

You can add a message to make test failures easier to understand.

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertNotNull;

class NullCheckTest {

    @Test
    void valueShouldBeNull() {
        String result = null;

        assertNull(result, "The result should be null");
    }

    @Test
    void valueShouldNotBeNull() {
        String result = "Hello JUnit";

        assertNotNull(result, "The result should not be null");
    }
}

Testing a Method That May Return Null

Suppose you have a method that returns a username:

class UserService {

    String findUsernameById(int id) {
        if (id == 1) {
            return "Alice";
        }
        return null;
    }
}

You can test both cases like this:

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertEquals;

class UserServiceTest {

    private final UserService userService = new UserService();

    @Test
    void findUsernameByIdReturnsNameWhenUserExists() {
        String username = userService.findUsernameById(1);

        assertNotNull(username);
        assertEquals("Alice", username);
    }

    @Test
    void findUsernameByIdReturnsNullWhenUserDoesNotExist() {
        String username = userService.findUsernameById(99);

        assertNull(username);
    }
}

Testing Null Arguments

If your code should reject null values, use assertThrows() to check that an exception is thrown.

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

class PersonTest {

    @Test
    void constructorThrowsExceptionWhenNameIsNull() {
        NullPointerException exception = assertThrows(
                NullPointerException.class,
                () -> new Person(null)
        );

        assertEquals("Name cannot be null", exception.getMessage());
    }
}

class Person {

    private final String name;

    Person(String name) {
        if (name == null) {
            throw new NullPointerException("Name cannot be null");
        }

        this.name = name;
    }
}

Summary

Use:

assertNull(value);
assertNotNull(value);

For null-related exceptions, use:

assertThrows(NullPointerException.class, () -> {
    // code that should throw NullPointerException
});

These assertions are the standard way to test null and non-null values in JUnit 5.

How do I use the safe call operator `?.` in Kotlin?

In Kotlin, the safe call operator ?. lets you access a property or call a function only if the value is not null.

If the value is null, the expression simply returns null instead of throwing a NullPointerException.

val name: String? = null

val length = name?.length

println(length) // null

Here, name is nullable because its type is String?. Since name is null, name?.length does not try to access .length; it returns null.

Basic syntax

nullableValue?.property
nullableValue?.function()

Example:

val user: User? = getUser()

val email = user?.email

If user is not null, email gets user.email.

If user is null, email becomes null.

Chaining safe calls

You can chain multiple safe calls together:

val city = user?.address?.city

This means:

  • if user is null, return null
  • otherwise check address
  • if address is null, return null
  • otherwise return city

Using ?. with a default value

Often, you combine ?. with the Elvis operator ?::

val length = name?.length ?: 0

This means:

  • if name is not null, use name.length
  • if name is null, use 0

Using ?.let

Use ?.let when you want to run code only when a value is not null:

val name: String? = "Kotlin"

name?.let {
    println("Name is $it")
    println("Length is ${it.length}")
}

The block runs only if name is not null.

Safe call on assignment

Safe calls can also be used on the left side of an assignment:

person?.address?.city = "Paris"

If person or address is null, the assignment is skipped.

Summary

val result = nullableValue?.someProperty

Use ?. when:

  • a value might be null
  • you want to avoid NullPointerException
  • returning null is acceptable when the receiver is null

Common pattern:

val result = nullableValue?.someProperty ?: defaultValue

How do I use Optional to refactor nested null checks?

Using Optional in Java is a great way to refactor nested null checks into more readable and maintainable code. Below, I’ll explain how you can use Optional to replace deeply nested null checks step by step with examples.


Example of Nested Null Checks

Consider this code with deeply nested null checks:

String streetName = null;

if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Street street = address.getStreet();
        if (street != null) {
            streetName = street.getName();
        }
    }
}

Here, multiple if statements are used to avoid NullPointerException. This can make the code verbose and harder to read.


Refactoring with Optional

You can refactor this using Optional to create a chain of operations that handle nulls more elegantly:

String streetName = Optional.ofNullable(user)
    .map(User::getAddress)  // get Address if user is not null
    .map(Address::getStreet) // get Street if Address is not null
    .map(Street::getName)    // get Name if Street is not null
    .orElse(null);           // return null if any step is null

This way, you eliminate the explicit null checks and reduce the overall complexity of the code.


Explanation of the Refactored Code

  • Optional.ofNullable(user)
    Wraps the user object in an Optional. If user is null, it creates an empty Optional to safely handle further processing.

  • .map()

    • Applies the method if the value is present; otherwise, it returns an empty Optional.
    • For example, map(User::getAddress) calls getAddress only if user is not null.
  • .orElse(null)
    Provides a fallback value in case the chain results in an empty Optional, i.e., if any intermediate object was null.


Variations

1. Provide a Default Value Instead of Null

You can replace null with any default value like this:

String streetName = Optional.ofNullable(user)
    .map(User::getAddress)
    .map(Address::getStreet)
    .map(Street::getName)
    .orElse("Default Street");

If user or any intermediate object is null, "Default Street" will be assigned to streetName.


2. Throw Exception if Value is Missing

String streetName = Optional.ofNullable(user)
    .map(User::getAddress)
    .map(Address::getStreet)
    .map(Street::getName)
    .orElseThrow(() -> new IllegalArgumentException("Street name not found!"));

This method will throw an exception if any object in the chain is null.


3. Perform an Action if Value Exists

You can perform a side effect or some action if the resulting value isn’t null:

Optional.ofNullable(user)
    .map(User::getAddress)
    .map(Address::getStreet)
    .map(Street::getName)
    .ifPresent(name -> System.out.println("Street: " + name));

This approach avoids the need to explicitly check equality with null.


Benefits of Using Optional for Null Checks

  1. Improved Readability:
    Eliminates nested if statements and reduces verbosity.

  2. Clear Intent:
    It’s evident that the code is handling potentially null objects.

  3. Avoid NullPointerException:
    Safeguards code without explicit null checks by the chaining mechanism.

  4. Encourages Functional Style:
    Methods like map, orElse, and ifPresent allow for a clean, declarative style of programming.


When Not to Use Optional

While Optional is a powerful tool, it’s not meant to replace all null checks. Avoid using Optional:

  1. For fields in entities/classes (use only for method return values).
  2. When null checks aren’t deeply nested (a simple if might be more appropriate).

With Optional, you get safer and cleaner null handling in your Java code, making it easier to maintain and debug!

How do I avoid null checks using Optional?

Using the Optional class in Java is a great way to handle the potential absence of a value and avoid explicit null checks in your code. Here’s a detailed explanation of how you can use Optional effectively to avoid null checks:


1. Use Optional Instead of null

Instead of returning null from a method, return an Optional instance. There are three main factory methods available:

  • Optional.of(value): Creates an Optional with the provided non-null value. Throws a NullPointerException if the value is null.
  • Optional.ofNullable(value): Creates an Optional with the given value, which can be null.
  • Optional.empty(): Returns an empty Optional.

Example:

package org.kodejava.util;

import java.util.Optional;

public class Example {
    public Optional<String> getName(String input) {
        return Optional.ofNullable(input);
    }
}

2. Access the Value Safely

To avoid null checks, you can access the value in an Optional using several methods:

2.1 isPresent() and get() (Not Preferred)

Before Java 11, developers often used isPresent to check if a value exists and then call get(). While functional, it’s not ideal because it still requires an “if-present” style:

String name = getName().isPresent() ? getName().get() : "default";

2.2 ifPresent()

Instead of checking isPresent, use the ifPresent method to perform an operation if the value exists:

Optional<String> name = getName("John");
name.ifPresent(n -> System.out.println("Name is: " + n));

2.3 orElse()

Provide a default value in case the Optional is empty:

String name = getName("John").orElse("default");
System.out.println(name);

2.4 orElseGet()

If providing a default value involves computation, use orElseGet. This will execute the supplier only when the Optional is empty:

String name = getName(null).orElseGet(() -> "computedDefault");

2.5 orElseThrow()

If the absence of a value is an error, throw an exception:

String name = getName(null).orElseThrow(() -> new IllegalArgumentException("Name is missing!"));

3. Transform the Value with map and flatMap

Instead of performing a null check and then transforming the value, use the map or flatMap methods to apply a function to the value inside the Optional:

Map Example:

Optional<String> name = getName("John");
Optional<Integer> nameLength = name.map(String::length);
nameLength.ifPresent(System.out::println); // Prints: 4

FlatMap Example:

Use flatMap when the function you’re applying returns another Optional:

Optional<String> email = getEmail();
Optional<String> domain = email.flatMap(e -> Optional.ofNullable(e.split("@")[1]));
domain.ifPresent(System.out::println);

4. Filter Optional Values

You can filter values inside an Optional using a predicate:

Optional<String> name = getName("John");
Optional<String> filteredName = name.filter(n -> n.startsWith("J"));
filteredName.ifPresent(System.out::println); // Prints: John

5. Chaining and Functional Style

Optional works well with lambda expressions and method references, encouraging a concise and functional programming style:

String name = getName(null)
                  .filter(n -> n.length() > 3)
                  .map(String::toUpperCase)
                  .orElse("DEFAULT");

System.out.println(name);

6. Avoid Misuse of Optional

  • Don’t use Optional as a method parameter. It should only be used for return types.
  • Don’t use Optional.get() without first checking isPresent(). This defeats the purpose of avoiding null.
  • Prefer specific methods like orElse or orElseThrow over manual isPresent() checks for better readability and safety.

Example: Practical Use in a Service

package org.kodejava.util;

import java.util.Map;
import java.util.Optional;

public class UserService {

    private final Map<Long, String> users =
            Map.of(1L, "Alice", 2L, "Bob", 3L, null);

    public Optional<String> getUserById(Long id) {
        return Optional.ofNullable(users.get(id));
    }

    public void displayUser(Long id) {
        getUserById(id)
                .map(String::toUpperCase)
                .ifPresentOrElse(
                        user -> System.out.println("User: " + user),
                        () -> System.out.println("User not found")
                );
    }
}

Output Example:

UserService service = new UserService();
service.displayUser(1L); // Prints: "User: ALICE"
service.displayUser(3L); // Prints: "User not found"

By using Optional this way, you can avoid null checks and make your code cleaner, safer, and more readable!

How do I use java.util.Optional class?

The java.util.Optional<T> class is a container object that may or may not contain a non-null value. It was introduced in Java 8 as part of the Java language’s growing emphasis on treating null values as an anti-pattern. Optional is a way of replacing a nullable T reference with a non-null but potentially empty Optional<T> reference.

In functional terminology, Optional is a monadic sequence of operations that can be combined to work with data in a declarative way, while deferring some operations, such as computations on elements.

Here are some useful methods that Optional class provides:

  1. Optional.of(T value): Returns an Optional with the specified present non-null value.
  2. Optional.empty(): Returns an empty Optional instance.
  3. Optional.ofNullable(T value): Returns an Optional describing the specified value, if non-null, otherwise returns an empty Optional.
  4. get(): If a value is present in this Optional, returns the value, otherwise throws NoSuchElementException.
  5. isPresent(): Returns true if there is a value present, otherwise false.
  6. ifPresent(Consumer<? super T> consumer): If a value is present, invokes the specified consumer with the value, otherwise does nothing.
  7. orElse(T other): Returns the value if present, otherwise returns other.
  8. orElseGet(Supplier<? extends T> other): Returns the value if present, otherwise returns the result produced by the supplying function.
  9. orElseThrow(Supplier<? extends X> exceptionSupplier): If a value is present, returns the value, otherwise throws an exception produced by the exception supplying function.

In practical terms, using Optional can help make your code more robust and reduce the likelihood of NullPointerException.

Here is a simple example:

package org.kodejava.util;

import java.util.Optional;

public class OptionalIntroduction {
    public static void main(String[] args) {
        Optional<String> opt = Optional.of("Hello, world!");
        if (opt.isPresent()) {
            System.out.println(opt.get());
        }
    }
}

This program will output: Hello, world!

We can utilize functional-style programming by using ifPresent() method provided by the Optional class. Here’s how:

package org.kodejava.util;

import java.util.Optional;

public class OptionalIfPresent {
    public static void main(String[] args) {
        Optional<String> opt = Optional.of("Hello, world!");
        opt.ifPresent(System.out::println);
    }
}

In this example, opt.ifPresent(System.out::println); is used to print the value of opt if it is present. The System.out::println syntax is a method reference in Java 8 that is functionally equivalent to value -> System.out.println(value). It will only execute System.out.println() if opt is not empty. Hence, it can be considered functional-style programming.

Here are another code snippet on using other methods from the java.util.Optional class:

package org.kodejava.util;

import java.util.Optional;

public class OptionalExample {
    public static void main(String[] args) {
        // Creating Optional objects
        // 1. Creates an empty Optional
        Optional<String> empty = Optional.empty();
        // 2. Creates an Optional with a non-null value
        Optional<String> nonEmpty = Optional.of("Hello");
        // 3. Creates an Optional with a null value
        Optional<String> nullable = Optional.ofNullable(null);

        // isPresent()
        // 1. Output: true
        System.out.println(nonEmpty.isPresent());
        // 2. Output: false
        System.out.println(empty.isPresent());

        // ifPresent()
        // 1. Output: Value is present: Hello
        nonEmpty.ifPresent(value -> System.out.println("Value is present: " + value));
        // 2. No output, since the Optional is empty.
        empty.ifPresent(value -> System.out.println("Value is present: " + value));

        // orElse()
        String valueFromNonEmpty = nonEmpty.orElse("Default Value");
        String valueFromEmpty = empty.orElse("Default Value");
        // Output: Hello
        System.out.println(valueFromNonEmpty);
        // Output: Default Value
        System.out.println(valueFromEmpty);

        // orElseGet()
        String valueFromNonEmptyWithSupplier = nonEmpty.orElseGet(() -> "Default Value");
        String valueFromEmptyWithSupplier = empty.orElseGet(() -> "Default Value");
        // Output: Hello
        System.out.println(valueFromNonEmptyWithSupplier);
        // Output: Default Value
        System.out.println(valueFromEmptyWithSupplier);

        // orElseThrow() when value is present it will return the value
        try {
            String value = nonEmpty.orElseThrow(IllegalArgumentException::new);
            System.out.println(value);
        } catch (IllegalArgumentException e) {
            //Handle exception
            e.printStackTrace();
        }
        // orElseThrow() when value is not present, it throws an exception
        try {
            String value = empty.orElseThrow(IllegalArgumentException::new);
            System.out.println(value);
        } catch (IllegalArgumentException e) {
            //Handle exception
            e.printStackTrace();
        }

    }
}

Output:

true
false
Value is present: Hello
Hello
Default Value
Hello
Default Value
Hello
java.lang.IllegalArgumentException
    at java.base/java.util.Optional.orElseThrow(Optional.java:403)
    at org.kodejava.util.OptionalExample.main(OptionalExample.java:53)

These methods are used to help in providing a more elegant way to handle null values in Java. Make sure to understand how and when to use each method to get the most out of the Optional class.