1, the preface

As a Java programmer, whether you’re a novice or a veteran, you’ve certainly encountered a variety of exceptions. In a foreign article, a ranking list of exception types was made, as shown in the figure below:

Yes, you read that right, NullPointerException tops the list.

Charles Antony Richard Hoare, the inventor of Null Reference, said, “I call it my billion-dollar mistake. This is the result of the invention of empty citation in 1965… This has resulted in countless errors, bugs, and system crashes that may have caused a billion dollars of pain and damage over the last 40 years.”

This may seem like an exaggeration, but there’s no denying that NullPointerException is a pain in the programmer’s heart, not that it’s hard to solve, but that it costs a lot more to solve.

I still remember when you were just starting out in the industry, you encountered bugs caused by NullPointerExceptions every day. After solving one bug, you encountered another. It also slowly teaches you not to trust any “object”, especially one provided to you by others, and to put judgment where it is used, so that you are much more comfortable. So the code usually looks like this:

String name = "Unknown"; if (null ! = people) { if (null ! = people.getName()) { name = people.getName(); } } return name;Copy the code

There is no need to worry about NullPointerExceptions, but too many judgment statements can cause a headache and the code becomes bloated. If the object is too complex, there are objects inside the object and so on, do you continue to judge layer by layer?

The exciting thing is that JDK1.8 has introduced a new class java.util.Optional

. With the Optional API, nullpointerexceptions are no longer needed, and we don’t have to write those annoying judgments.

2, Optional classes

For example, using the new class means that if you know that a Person may or may not have a car, the CAR variable inside the Person class should not be declared as CAR and assigned a null reference to it when encountering someone who does not have a car. Instead, it should be declared directly as Optional, as shown in the following figure.

When a variable exists, the Optional class simply wraps the class. When the variable does not exist, the missing value is modeled as an “empty” Optional object returned by the option.empty () method. The optional.Empty () method is a static factory method that returns a specific single instance of the Optional class.

Optional, which is essentially a container object, has a non-null value or null value that we pass into the container. If the value exists, the optional.isPresent () method returns true and gets the value via the option.get () method.

The Optional object constructor is private. You cannot create an Optional object directly using new. You can only create an Optional object using static methods provided by Optional.

Optional provides the following creation methods:

  • Optional.of(obj): If the object isnull, will throwNullPointerException.
  • Optional.ofNullable(obj): If the object is null, an object with no value will be createdEMPTY OptionalObject instance (new Optional<>()).
  • Optional.empty(): equivalent toOptional.ofNullable(null).

The source code fragment is as follows:

/**
 * Constructs an instance with the value present.
 *
 * @param value the non-null value to be present
 * @throws NullPointerException if value is null
 */
private Optional(T value) {
    this.value = Objects.requireNonNull(value);
}

……

/**
 * Returns an {@code Optional} with the specified present non-null value.
 *
 * @param <T> the class of the value
 * @param value the value to be present, which must be non-null
 * @return an {@code Optional} with the value present
 * @throws NullPointerException if value is null
 */
public static <T> Optional<T> of(T value) {
    return new Optional<>(value);
}
Copy the code
/**
 * Returns an {@code Optional} describing the specified value, if non-null,
 * otherwise returns an empty {@code Optional}.
 *
 * @param <T> the class of the value
 * @param value the possibly-null value to describe
 * @return an {@code Optional} with a present value if the specified value
 * is non-null, otherwise an empty {@code Optional}
 */
public static <T> Optional<T> ofNullable(T value) {
    return value == null ? empty() : of(value);
}
Copy the code
/** * Common instance for {@code empty()}. */ private static final Optional<? > EMPTY = new Optional<>(); ... /** * Returns an empty {@code Optional} instance. No value is present for this * Optional. * * @apiNote Though it may be  tempting to do so, avoid testing if an object * is empty by comparing with {@code ==} against instances returned by * {@code Option.empty()}. There is no guarantee that it is a singleton. * Instead, use {@link #isPresent()}. * * @param <T> Type of the non-existent value * @return an empty {@code Optional} */ public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; }Copy the code

Highly recommended useOptional.ofNullable(obj)Method to createOptionalObject and get the corresponding value.

3. Use of Optional

By now you’ve seen the benefits of Optional, but how can you use it?

Create an Optional object that accepts NULL values using the static engineering method option.ofNullable (obj) :

Optional<People> optional = Optional.ofNullable(people);
Copy the code

Even if people is null, the optional object is just an empty object.

If people is not null, return true according to option.isPresent () and get the value via option.get ().

To avoid NPE, the optional.isPresent () method already evaluates null and returns true if it exists.

People p = null;
if (optional.isPresent()) {
    p = optional.get();
}
Copy the code

Looking at this, you might notice that this is no different from a NULL judgment check.

It wasn’t until I looked at Optional’s other apis that I realized its real value.

3.1 Optional.map

Getting a property from an object is the most common operation. For example, you might need to get the name from the people object. Before retrieving the name, you need to check whether the people object is null, as shown below:

String name = null; if (null ! = people) { name = people.getName(); }Copy the code

Using the optional. map method, you can write:

Optional<People> optional = Optional.ofNullable(people);
Optional<String> stringOptional = optional.map(People::getName);
Copy the code

3.2 Optional.orElse

When an object is null, it is often possible to set a default value for the business to continue the process.

String name = null ! = people ? people.getName() : "Unknown";Copy the code

Or throw an exception.

if (null ! = people.getName()) { throw new RuntimeException(); }Copy the code

The Optional class provides two methods, orElse and orElseThrow, to facilitate the above transformation.

// Set default value String name = optional.orelse (new People("Unknown")).getName(); String name = optional.orelsethrow (RuntimeException::new).getName();Copy the code

If optional is empty, provide a default value or throw an exception.

3.3 Optional.filter

Often you need to call a method on an object to look at some of its properties. For example, you might want to check if the name is “xcbeyond.” To do this in a safe way, you first need to check whether the people object is null and then call its method getName, as shown below:

if (null ! = people && "xcbeyond".equals(people.getName())) { System.out.println("ok"); }Copy the code

The Optional class provides a method called filter that can be refactored nicely:

optional.filter(people1 -> "xcbeyond".equals(people.getName()))
		.ifPresent(x -> System.out.print("ok"));
Copy the code

Optional Refactor the code

Let’s look at the code at the beginning of the article again:

String name = "Unknown"; if (null ! = people) { if (null ! = people.getName()) { name = people.getName(); } } return name;Copy the code

With Optional in mind, refactor the code:

Optional<People> optional = Optional.ofNullable(people);
return optional.map(People::getName).orElse("Unknown");
Copy the code

Combined with Optional and Lambda expressions, it is clear that the refactoring makes the code more fluid and coherent, and improves the overall readability of the code.

Reference article:

1.Dzone.com/articles/th…

2. Java 8 In Action