Optional makes programming more interesting

In short, Opitonal class is provided by Java. In order to solve the problem that we usually judge whether the object is empty, we will use null= The existence of obj is a headache, leading to NPE (Null Pointer Exception). At the same time, the existence of Optional can make the code simpler, more readable and more efficient

General judgment:

//Target person
//The attributes are name and age
Person person=new Person();
if (null==person){
     return "person by null";
 }
return person;

Using Optional:

//Target person
//The attributes are name and age
Person person=new Person();
return Optional.ofNullable(person).orElse("person by null");

Test and display class Person code (if a friend doesn't understand, you can take a look at this):

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() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

Next, let's efficiently learn about the magical Optional class!

2.1 creation of optional object

First of all, let's open the interior of Optional to explore. We first extracted several methods to 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
   //It means that we can't go outside to new and come out with Optional objects
   private Optional() {
        this.value = null;
    }
   private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }
    //This static method basically creates an object with an empty wrapper value, because there is no parameter assignment
   public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }
    //This static method is roughly to create an object with non empty packing value 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 parameter value is empty, and creates a parameterized object if it is not empty
   public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }
 }

Then make a simple example to show the correspondence with the above

//1. Create an Optional object with empty packing object value
Optional<String> optEmpty = Optional.empty();
//2. Create an Optional object with non empty packing object value
Optional<String> optOf = Optional.of("optional");
//3. Create an Optional object whose value can be empty or not
Optional<String> optOfNullable1 = Optional.ofNullable(null);
Optional<String> optOfNullable2 = Optional.ofNullable("optional");

We have roughly analyzed the internal methods of creating Optional objects, and then formally enter the learning and use of Optional

2.2 Optional. Value returned by get () object

The return value of the option () method of the source code is:

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

That is, if value is not empty, it will be returned. If it is empty, an exception "No value present" will be thrown. The simple example is displayed

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

2.3 Optional.isPresent() method (judge whether it is empty)

isPresent() method will return a boolean value. If the object is not empty, it will be true. If it is empty, it will be false. Source code:

 public boolean isPresent() {
        return value != null;
    }

Simple example:

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

2.4 Optional.ifPresent() method (judge whether it is empty and return the function)

This means that if the object is not empty, run the function body source code:

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

See the example:

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

If the object is not null, the age will be printed. Because NPE (non null judgment) has been made internally, there is no need to worry about null pointer exceptions

2.5 Optional.filter() method (filter object)

The filter() method roughly means to accept an object and filter it conditionally. If the conditions meet, it returns the Optional object itself. If not, it returns null Optional

Source code:

public Optional<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    //If it is empty, return this directly
    if (!isPresent())
        return this;
    else
    //Determine whether the return itself is empty or Optional
        return predicate.test(value) ? this : empty();
}

Simple example:

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

2.6 Optional.map() method (secondary packaging of objects)

The map() method performs a secondary operation on the object in the corresponding function interface, encapsulates it into a new object, and then returns the source code in Optional:

 public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        //If it is empty, return to yourself
        if (!isPresent())
            return empty();
        else {
        //Otherwise, the Optional modified by the method is returned
            return Optional.ofNullable(mapper.apply(value));
        }
    }

Example display:

Person person1=new Person();
person.setAge(2);
String optName = Optional.ofNullable(person).map(p -> person.getName()).orElse("name Empty");

2.7 Optional.flatMap() method (optional object for secondary packaging)

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

    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));
        }
    }

example:

Person person=new Person();
person.setAge(2);
Optional<Object> optName = Optional.ofNullable(person).map(p -> Optional.ofNullable(p.getName()).orElse("name Empty"));

2.8 Optional.orElse() method (null return object)

One of the common methods. This method means that if the wrapped object is empty, execute the value in the orElse method. If it is not empty, return the source code of the written object:

public T orElse(T other) {
//If it is not empty, return value; if it is empty, return other
    return value != null ? value : other;
}

example:

Person person1=new Person();
person.setAge(2);
Optional.ofNullable(person).orElse(new Person("Xiao Ming", 2));

2.9 Optional.orElseGet() method (null returns the Supplier object)

This is very similar to orElse. The input parameter is different. The input parameter is a Supplier object. If it is empty, it returns the value of the incoming object get() method. If it is not empty, it returns the source code of the current object:

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

example:

Optional<Supplier<Person>> sup=Optional.ofNullable(Person::new);
//Call the get() method, and then the construction method of the object will be called, that is, the real object will be obtained
Optional.ofNullable(person).orElseGet(sup.get());

To be honest, I was puzzled about the Supplier object. I found out that Supplier is also a way to create objects by simply checking it on the Internet. In short, Supplier is an interface, which is a lazy load similar to Spring. After declaration, it will not occupy memory. Only after the get() method is executed, will the construction method be called to create objects. The syntax of creating objects is Supplier < person > supperson = person:: new;

Supperson Get()

2.10 Optional.orElseThrow() method (null returns exception)

Personally, I often use this method in actual combat. The function of this method is to throw the exception you defined if it is empty. If it is not empty, return the current object. In actual combat, all exceptions must be handled well for the sake of code readability

Source code:

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

Example: This is the actual combat source code

//A simple query
Member member = memberService.selectByPhone(request.getPhone());
Optional.ofNullable(member).orElseThrow(() -> new ServiceException("There is no relevant data to query"));

2.11 comparative analysis of similar methods

Maybe when you see this, if you haven't used it before, you will think that orElse() and orElseGet() and orElseThrow() are very similar, and map() and flatMap() are very similar

Hahaha, don't worry. It's all from this step. I'll summarize the similarities and differences of different methods

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

The effect of the method is similar. If the object is not empty, the object is returned. If it is empty, the corresponding parameters in the method body are returned. Therefore, it can be seen 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

The effect of the method is similar. The method parameters are repackaged and returned. The input parameters are different

  • map (function)

  • flatmap (optional < function > function)

How to use it should be defined according to business scenarios and code specifications. Here's a brief look at how I use the magical option in practice

3. Reproduction of actual combat scene

Scenario 1: query an object in the service layer, judge whether it is empty after returning and handle it

 //Query an object
 Member member = memberService.selectByIdNo(request.getCertificateNo());
 //Use ofNullable plus orElseThrow for judgment and operation
 Optional.ofNullable(member).orElseThrow(() -> new ServiceException("There is no relevant data to query"));

Scenario 2: we can add Optional when defining the return value in the dao interface layer. For example, I use jpa, and so do others

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

Then in the Service

public TerminalVO findById(String id) {
//This method also uses Optional packaging in dao layer
        Optional<Terminal> terminalOptional = terminalRepository.findById(id);
        //Directly use isPresent() to determine whether it is empty
        if (terminalOptional.isPresent()) {
        //Use the get() method to get the object value
            Terminal terminal = terminalOptional.get();
            //In actual combat, we have eliminated the tedious task of using set to assign values, and directly use BeanCopy to assign values
            TerminalVO terminalVO = BeanCopyUtils.copyBean(terminal, TerminalVO.class);
            //Call dao layer method to return 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("The terminal does not exist");
    }

There are many actual combat scenarios, including whether to return the current value or jump to another method body when returning. If you have no experience and want to learn, you can comment and I will reply to you

4. Precautions for optional use

Optional is really easy to use. Can it completely replace if judgment?

I think this must be the idea that you may have after using Optional. The answer is No

Take the simplest Chestnut:

Example 1:

What if I just want to judge whether a variable of the object is empty and make a judgment?

Person person=new Person();
person.setName("");
persion.setAge(2);
//General judgment
if(StringUtils.isNotBlank(person.getName())){
  //Execute code block whose name is not empty
}
//Use Optional for judgment
Optional.ofNullable(person).map(p -> p.getName()).orElse("name Empty");

I think this example can well illustrate this problem. It's just a very simple judgment. if Optional is used, we also need to consider the packaging value, code writing and method call. Although there is only one line, the readability is not good. if other programmers read it, I don't think it's obvious

5.jdk1.9 optimization of Optional

First, three methods are added:

  • or(), ifpresentoelse(), and stream().

  • or() is similar to orElse and other methods. If the object is not empty, it returns the object. If it is empty, it returns the preset value in the or() method.

  • The ifpresentoelse () method has two parameters: a Consumer and a Runnable. If the object is not empty, the action of Consumer will be executed; otherwise, Runnable will be run. There is more OrElse judgment than ifPresent().

stream() converts Optional into stream. If there is a value, it returns the stream containing the value. If there is no value, it returns an empty stream.

Because of this jdk1 I didn't test the Optional of 9. At the same time, I also found that there are good articles that can make you understand jdk1 I won't go into the optimization of option of 9.

Tags: Java optional programming language

Posted by xhelle on Wed, 18 May 2022 00:26:51 +0300