NullPointerException — NullPointerException is one of the most common exceptions in a program, and a common exception that causes a program to fail. Previously, to prevent null, we used to use if… The else… Doing defensive checks, Guava later introduced the Optional class to address code contamination caused by the above method.

Java8 borrowed from Guava’s Optional and added the Optional class of the same name. The Optional class provides a number of useful methods to avoid nullpointerexceptions by avoiding null pointer judgments.

Common methods

Let’s walk through the methods provided by the Optional class.

Method of
public static <T> Optional<T> of(T value) {
    return new Optional<>(value);
}
Copy the code

The Optional constructor is private. You cannot create an Optional object externally using new. However, the Optional class provides three methods to obtain an Optional instance object. The of method is used to create an Optional instance that wraps the object with a non-empty value and throws a NullPointerException if the value is empty.

// If user is null, NullPointerException is raised Optional< user > optional_user = Optional. Of (user);Copy the code
OfNullable method
public static <T> Optional<T> ofNullable(T value) {
    return value == null ? empty() : of(value);
}
Copy the code

One of the methods to get an Optional instance object that returns an Optional instance object that allows the wrapper object to have a null value. OfNullable differs from the of method in that it allows the wrapped object to be null.

Optional_user1 == optional_user2 = true Optional<User> Optional_user1 = optional_ofNullable (null); Optional<User> optional_user2 = Optional.ofNullable(null);Copy the code
The empty methods
public static<T> Optional<T> empty() {
    @SuppressWarnings("unchecked")
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}
Copy the code

One way to get an Optional instance object is to create an Optional instance object that wraps the object with a null value.

// Return Optional<User> optional_user = option.empty (); // Return Optional<User> optional_user = optional_empty ();Copy the code
IsPresent method
public boolean isPresent() { return value ! = null; }Copy the code

Determines whether the wrapper object value is null.

Optional< user > optional_user1 = option.ofnullable (user); Optional<User> optional_user2 = Optional.ofNullable(null); // Return true optional_user1.isPresent(); // Return false optional_user2.isPresent();Copy the code
IfPresent method
public void ifPresent(Consumer<? super T> consumer) { if (value ! = null) consumer.accept(value); }Copy the code

The accept() method of the Consumer object is called if the value of the wrapper object is empty or not.

Option.ofnullable (user).ifPresent(() -> {// wrap object value for null execution code...... });Copy the code
The get method
public T get() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}
Copy the code

Returns the value of the wrapped object, or throws NoSuchElementException if empty.

OrElse method
public T orElse(T other) { return value ! = null ? value : other; }Copy the code

Returns the actual value of the wrapped object if it is not NULL, or the specified value if it is null, that is, the passed argument.

Optional.ofNullable(user).orElse(new User("zhangsan", 20));
Copy the code
OrElseGet method
public T orElseGet(Supplier<? extends T> other) { return value ! = null ? value : other.get(); }Copy the code

This works the same way as the orElse method, except that orElseGet takes the Supplier object as an entry. When the Optional wrapper object is null, the Supplier returns the specified value generated by the Supplier get method.

// name is a String object optional.ofnullable (name).orelseget (() -> "zhangsan");Copy the code
OrElseThrow method
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}
Copy the code

OrElseGet returns the value of the wrapper object if it is not empty, or a Throwable exception if it is empty.

The filter method
public Optional<T> filter(Predicate<? super T> predicate) { Objects.requireNonNull(predicate); if (! isPresent()) return this; else return predicate.test(value) ? this : empty(); }Copy the code

Filters Optional wrapper objects. Returns the Optional instance if the wrapper meets the conditions of Predicate, or the Optional instance if the wrapper object is null.

// 过滤name为zhangsan的User,当不存在时打印提示信息
Optional.ofNullable(user)
	.filter(u -> u.getName.equals("zhangsan"))
	.ifPresent(() -> System.out.println("There is no zhangsan"));
Copy the code
The map method
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Optional.ofNullable(mapper.apply(value));
    }
}
Copy the code

The map method performs a Function operation on the wrapper (that is, calling Function’s Apply method) and returns a new Optional instance. The new Optional instance can be of any type (not necessarily the same type as the original wrapper).

If the wrapper object is null, an Optional instance of the wrapper object is still returned. Map can be called at an infinite level.

// Return an Optional<String> option.of (user).map(u -> u.getName());Copy the code
FlatMap method
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Objects.requireNonNull(mapper.apply(value));
    }
}
Copy the code

The mapper method can return any type of value, while the mapper method of flatMap returns an Optional value. The Map method automatically returns an Optional value.

FlatMap (u -> Optional. Of (user).flatmap (u -> Optional. Of (u.getName())));Copy the code
To solve the NPE

Before Optional, we’ll use if… The else… Do defensive checks to prevent null pointer exceptions.

public String getUserName(User user) {
  if(user == null) {
    return "unknown";
  }
  return user.getName();
}
Copy the code

With Optional, we can do just that…

public String getUserName(User user) { Optional<User> optional_user = Optional.ofNullable(user); if(! optional_user.isPresent()) { return "unknown"; } return user.getName(); }Copy the code

Ah… This……

Obviously the two methods are not fundamentally different, both still have defensive checks, and both are still not concise enough. The second method, however, uses the isPresent method to replace the null judgment displayed.

Correct posture.

Public String getUserName(User User) {// Return optional.ofnullable (User).map(u -> u.get_name ()) .orElse("unkonwn"); }Copy the code

This example does not fully demonstrate Optional’s strength, but look at the following example.

/** * public String getBossName(User User) {if(User User! = null) { Company company = user.getCompany(); if(company ! = null) { Boss boss = company.getBoss(); if(boss ! = null) { return boss.getName(); } } } return "unkonwn"; }Copy the code

Graceful posture.

/** * get the name of the leader, Use Optional * */ public String getBossName(User User) {return optional.ofnullable (User).map(u -> u.getCompany()).map(c)  -> c.getBoss()) .map(b -> b.getName()) .orElse("unkonwn"); }Copy the code

Using Optional will make our code extremely elegant and concise.

* Like a small partner move small hands, little attention. Follow the official wechat account [programmer Mark Chou] to get more advanced Java architecture materials (“Spring Cloud micro services practice“”Deep analysis of Spring source code“”In-depth understanding of Apache Dubbo and combat“”Practice guide for front-line architects“”25 topics Java Interview Questions Manual“”Java surface by“…) .