preface

Java (NPE) Null Pointer Exception (NPE) Null Pointer Exception (NPE)

We are going to use the new Java8 feature Optional to simplify code as much as possible and efficiently handle NPE (Null Pointer Exception)

2. Meet Optional and use it

In short, Opitonal class is provided by Java in order to solve the problem that you usually determine whether an object is empty, will use null! =obj exists in such a way.

NPE (Null Pointer Exception) and Optional can make code simpler, more readable and more efficient. General judgment:

// Object person attributes have name, age
Person person=new Person();
if (null==person){
  return "The person is null";
}
return person;
Copy the code

Optional:

// Object person attributes have name, age
Person person=new Person();

return Optional.ofNullable(person).orElse("The person is null");
Copy the code

The test shows the Class Person code (take a look at this if you don’t understand) :

public class Person {
    private String name;
    private Integer age;
    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    public Person() {
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        returnage; } public void setAge(Integer age) { this.age = age; }}Copy the code

Below, we will learn about the magical Optional class efficiently!

2.1 Optional object Creation

So let’s go inside Optional and take a look at some of the ways that we can create Optional objects

public final class Optional<T> { private static final Optional<? > EMPTY =new Optional<>();
  private final T value;
  // We can see that both construction squares are private
  // We can't create Optional objects outside
  private Optional() {
      this.value = null;
  }
  private Optional(T value) {
      this.value = Objects.requireNonNull(value);
  }
  // This static method basically creates an object whose wrapper value is empty because there are no arguments assigned
  public static<T> Optional<T> empty() {
      @SuppressWarnings("unchecked")
      Optional<T> t = (Optional<T>) EMPTY;
      return t;
  }
  // This static method basically creates an object with a wrapper value that is not empty because of the assignment
  public static <T> Optional<T> of(T value) {
      return new Optional<>(value);
  }
  // This static method basically creates an empty object if the argument value is null, and a parameterized object if it is not
  public static <T> Optional<T> ofNullable(T value) {
      returnvalue == null ? empty() : of(value); }}Copy the code

Do a simple example to show the corresponding above

// create an Optional object that wraps the object with an empty value
Optional<String> optEmpty = Optional.empty();
// create an Optional object that wraps the object with a non-empty value
Optional<String> optOf = Optional.of("optional");
// create an Optional wrapper object whose value can be empty or non-empty
Optional<String> optOfNullable1 = Optional.ofNullable(null);
Optional<String> optOfNullable2 = Optional.ofNullable("optional");
Copy the code

Now that we’ve done an overview of the internal methods for creating Optional objects, we’re going to start looking at Optional.

2.2 Optional. The get () method

The get() method returns an instance value of an option.

public T get() {
  if (value == null) {
      throw new NoSuchElementException("No value present");
  }
  return value;
}
Copy the code

That is, if value is not null, return, if value is null, throw an exception “No value present” example

Person person=new Person();
person.setAge(2);
Optional.ofNullable(person).get();
Copy the code

2.3 Optional. IsPresent () method

The isPresent() method returns a Boolean value, true if the object is not empty, false if it is empty.

public Boolean isPresent() {
    returnvalue ! = null; }Copy the code

A simple example shows:

Person person=new Person();
person.setAge(2);
if (Optional.ofNullable(person).isPresent()){
    // Write non-null logic
    System.out.println("Not empty");
} else{
    // Write to empty logic
    System.out.println("Empty");
}
Copy the code

2.4 Optional. IfPresent () method

If the object is not empty, run the function body.

public void ifPresent(Consumer<? super T> consumer) {
  // If value is not null, the accept body is run
  if(value ! = null) consumer.accept(value); }Copy the code

See instances:

Person person=new Person();
person.setAge(2);
Optional.ofNullable(person).ifPresent(p -> System.out.println("Age"+p.getAge()));
Copy the code

If the object is not empty, the age is printed, because NPE has already been done internally, so you don’t have to worry about null-pointer exceptions.

2.5 Optional. The filter () method

The filter() method basically means that we take an object and filter it with criteria, returning the Optional object itself if the criteria are met, and empty Optional if not.

public Optional<T> filter(Predicate<? super T> predicate) {
  Objects.requireNonNull(predicate);
  // Return this if null
  if(! isPresent())return this;
  else
    // Check whether the return itself is empty Optional
    return predicate.test(value) ? this : empty();
}
Copy the code

A simple example:

Person person=new Person();
person.setAge(2);
Optional.ofNullable(person).filter(p -> p.getAge()>50);
Copy the code

2.6 Optional. The map () method

The map() method performs a quadratic operation on an object corresponding to the Funcation interface, encapsulates it into a new object and returns it in Optional:

public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    // Return itself if null
    if(! isPresent())return empty();
    else {
        // Otherwise return Optional decorated with the method
        returnOptional.ofNullable(mapper.apply(value)); }}Copy the code

Examples show:

Person person1=new Person();
person.setAge(2);
String optName = Optional.ofNullable(person).map(p -> person.getName()).orElse("The name is empty." ");
Copy the code

2.7 Optional. FlatMap () method

The map() method performs a secondary operation on the object corresponding to the Optional< Funcation > function interface, encapsulates it into a new object and returns it in Optional:

public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
    Objects.requireNonNull(mapper);
    if(! isPresent())return empty(); 
    else {
        returnObjects.requireNonNull(mapper.apply(value)); }}Copy the code

Example:

Person person=new Person();
person.setAge(2);
Optional<Object> optName = Optional.ofNullable(person)
  .map(p -> 
    Optional.ofNullable(p.getName())
    .orElse("The name is empty." "));
Copy the code

2.8 Optional. OrElse () method

If the object is empty, execute the value of the orElse method. If the object is not empty, return the source code of the write object.

public T orElse(T other) {
  // If not empty, return value, if empty, return other
  returnvalue ! = null ? value : other; }Copy the code

2.9 Optional. OrElseGet () method

This is similar to orElse, except that the input parameter is the Supplier object, which is empty and returns the. Get () method of the passed object, or the current object if it is not empty:

public T orElseGet(Supplier<? extends T> other) {
  returnvalue ! = null ? value : other.get(); }Copy the code

Example:

Optional<Supplier<Person>> sup=Optional.ofNullable(Person::new);

// Call the get() method, at which point the constructor of the object is called, i.e. the real object is obtained
Optional.ofNullable(person).orElseGet(sup.get());
Copy the code

Supplier is also a way to create objects. Simply put, Suppiler is an interface that is lazy like Spring and does not consume memory after being declared.

The constructor is called to create the object only after the get() method is executed. The syntax for creating the object is Supplier supPerson= Person::new; Supperson.get () will do if needed

2.10 Optional. OrElseThrow () method

This I personally in the actual practice also often use this method, method function is if empty, throw you define the exception, if not empty to return the current object, in the actual practice all exceptions must be handled well, for the readability of the code source:

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if(value ! = null) {return value;
    } else{ throw exceptionSupplier.get(); }}Copy the code

Example: This post actual combat source code

// A simple query
Member member = memberService.selectByPhone(request.getPhone());

Optional.ofNullable(member).orElseThrow(() -> new ServiceException("No query related data"));
Copy the code

2.11 Comparative analysis of similarity methods

OrElse () is similar to orElseGet() and orElseThrow(), and map() is similar to flatMap().

Ha ha ha don’t worry, all come from this step, I will give you a summary of the differences and similarities of different methods

Similarities and differences between orElse() and orElseGet() and orElseThrow()

If the object is not empty, the object is returned. If the object is empty, the corresponding parameter in the method body is returned. So we can see that the parameters in the three method bodies are different

  • OrElse (T object)
  • OrElseGet (Supplier < T > object)
  • OrElseThrow (exception)

Similarities and differences between Map () and orElseGet

  • Method effect is similar, the method parameters are wrapped twice, and return, the input parameter is different
  • Map (function function)
  • Flatmap (Optional< function > function)

How can I use the magic Optional option in real life

3. Actual combat scene reproduction

Scenario 1:

Query an object in the Service layer, return it to determine whether it is empty and process it

// Query an object
Member member = memberService.selectByIdNo(request.getCertificateNo());
// use ofNullable and orElseThrow to judge and manipulate
Optional.ofNullable(member).orElseThrow(() -> new ServiceException("No query related data"));
Copy the code

Scenario 2:

We can define the return value in the DAO interface layer with Optional for example: I use JPA, and so on

public interface LocationRepository extends JpaRepository<Location, String> {
  Optional<Location> findLocationById(String id);
}
Copy the code

But in Service

public TerminalVO findById(String id) {
  // This method is also wrapped Optional in the DAO layer
  Optional<Terminal> terminalOptional = terminalRepository.findById(id);
  // Use isPresent() directly to check whether isPresent() is null
  if (terminalOptional.isPresent()) {
  // Use the get() method to get the object value
      Terminal terminal = terminalOptional.get();
      // We can use BeanCopy instead of set to assign values
      TerminalVO terminalVO = BeanCopyUtils.copyBean(terminal, TerminalVO.class);
      // Call the DAO layer method to return the wrapped object
      Optional<Location> location = locationRepository.findLocationById(terminal.getLocationId());
      if (location.isPresent()) {
          terminalVO.setFullName(location.get().getFullName());
      }
      return terminalVO;
  }
  // Don't forget to throw an exception
  throw new ServiceException("This terminal does not exist");
}
Copy the code

4.Optional use

Can Optional completely replace if?

I’m sure that’s what you might think after you use Optional, and the answer is no. Here’s the simplest one:

Example 1:

What if I just want to determine whether a variable of the object is empty and make that determination?

Person person=new Person();
person.setName("");
persion.setAge(2);
// Common judgment
if(StringUtils.isNotBlank(person.getName())){
  // Execute code block with non-empty name
}
// Use Optional
Optional.ofNullable(person).map(p -> p.getName()).orElse("The name is empty." ");
Copy the code

I think this is a good example of that, but it’s a very simple judgment.

If we use Optional we also have to think about wrapping values, we have to think about code writing, we have to think about method calls.

Although it is only one line, it is not very readable. If other programmers read it, I think it is not as obvious as if

5. Jdk1.9 optimized for Optional

Three methods were first added: OR (), ifPresentOrElse(), and stream()

Or () is similar to methods such as orElse in that it returns an object if it is not empty, or the default value in the or() method if it is empty.

The ifPresentOrElse() method takes two arguments: a Consumer and a Runnable. If the object is not empty, the action Consumer is performed, otherwise Runnable is run. There are more OrElse judgments than ifPresent ().

Stream () converts Optional to stream, returning the stream containing the value if there is a value, and the empty stream if there is no value.

Because this JDK1.9 Optional specific I did not test, but also found that there is a pretty good article has also let you understand jdK1.9 option optimization, I will not go into the details.

Source: juejin. Im /post/684490…