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.