“This is the sixth day of my participation in the First Challenge 2022. For details: First Challenge 2022”

preface

Hello everyone, MY name is Kano, a full stack full stick engineer!

As a javaer, Java. Lang. NullPointerException (hereinafter referred to as: NPE is probably one of our most common exceptions, and to avoid this problem we usually do if checks where null is likely to occur, which can sometimes result in deep levels of nesting, resulting in code bloat (more code), poor readability, and difficult maintenance. To address this issue, Java8 introduced the Optional class. This chapter will focus on the Optional class. We hope you can learn more about Optional.

Introduction to the

Optional is a container object that can hold a value of a generic type, either null or non-null. Optional can use its own container methods to determine whether a value exists and retrieve the value stored in the container.

Case preparing

We prepare a House with a Door that contains a Type and a method getDoorTypeName that gets the name of the Type

@Data
public class House {

    private Door door;
    
    public String getDoorTypeName(a) {
        return door.getType().getName();
    }

    @Data
    static class door {
        private Type type;
    }

    @Data
    static class Type {
        privateString name; }}Copy the code

NPE demo

Gets the type name of the gate

public void testNPE(a){
    System.out.println(new House().getDoorTypeName()); // java.lang.NullPointerException
}
Copy the code

If solve the NPE

The getOptimizeDoorTypeName method is added to House, and empty judgment is performed inside the method

public String getOptimizeDoorTypeName(a) {
    if(door ! =null) {
        Type type = door.getType();
        if(type ! =null) {
            returntype.getName(); }}return "Unknown type";
}
Copy the code

There is a problem with the above method, if the level of nesting is deep, the code can be said to be quite bloated, for this problem, we quickly invite the author of this article’s main character Optional!

Optional User Guide

Optional is a final class and cannot be inherited. The Optional constructor is also private, so we can’t use the new keyword to create Optional objects. Of course, Java designers don’t have to use the new keyword. Optional provides more convenient of and ofNullable for Optional objects.

Optional container creation method

  • Creation Methods Overview
methods note
public static Optional empty() Returns an empty container with an empty internal value
public static Optional of(T value) Create a container based on value. Value cannot be empty. If it is empty, raise an NPE exception
public static Optional ofNullable(T value) Create a container based on valueempty(), not empty is equal toof()
  • Code demo
public void testOptional(a){
    Optional<House> houseEmpty = Optional.empty();
    Optional<House> houseOfNullable = Optional.ofNullable(null);
    Optional<House> houseOfNotNullable = Optional.ofNullable(new House());
    Optional<House> houseOf = Optional.of(new House());
    Optional<House> houseOfNull = Optional.of(null); / / NPE anomalies
}
Copy the code

Optional container object method

  • List of methods
methods note
public T get() Gets an Optional value that does not have a NoSuchElementException
public boolean isPresent() Check whether the Optional value exists
public void ifPresent(Consumer<? super T> consumer) If the Optional value exists, the value is acted on by the passed consumer, otherwise nothing is done
public T orElse(T other) Return Optional if the value is not empty, otherwise return Other
public T orElseGet(Supplier<? extends T> other) Return Optional if the value is not empty, otherwise generate another based on other
public T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X If Optional is not empty, it is returned; otherwise, an exception generated by supplier is thrown
public Optional filter(Predicate<? super T> predicate) Value exists and matches the passed predicate, returns the Optional containing the value, otherwise returns an empty Optional
public Optional map(Function<? super T, ? extends U> mapper) If Optional sets a value, mapper is called to process the value and returns Optional wrapped U, otherwise empty Optional is returned
public Optional flatMap(Function<? super T, Optional> mapper) This is similar to the map() method, except that the mapper is already an Optional result
  • Code demo
public void testOptionalMethod(a){
    Optional<House> houseOptional = Optional.of(new House());
    House houseHasDoor = new House();
    houseHasDoor.setDoor(new House.Door());
    Optional<House> houseOptionalHasDoor = Optional.of(houseHasDoor);
    Optional<House> houseNullOptional = Optional.empty();
    // get
    System.out.println("get " + houseOptional.get()); // get House(door=null)
    // isPresent
    System.out.println("isPresent " + houseOptional.isPresent()); // isPresent true
    // ifPresent(Consumer<? super T> consumer)
    houseOptional.ifPresent(System.out::println); // House(door=null)
    // orElse
    House houseElse = houseNullOptional.orElse(new House());
    System.out.println("orElse " + houseElse); // orElse House(door=null)
    // orElseGet
    House houseElseGet = houseNullOptional.orElseGet(House::new);
    System.out.println("orElseGet " + houseElseGet); // orElseGet House(door=null)
    // filter
    Optional<House> house = houseOptional.filter(Objects::nonNull);
    Optional<House> houseNull = houseNullOptional.filter(Objects::nonNull);
    System.out.println("filter " + house + "" + houseNull); // filter Optional[House(door=null)] Optional.empty
    // map, flatMap returns null
    Optional<House.Door> door = houseOptional.map(House::getDoor);
    Optional<House.Door> doorFromFlatMap = houseOptional.flatMap(item -> Optional.of(new House.Door()));
    System.out.println("empty map " + door + " flatMap " + doorFromFlatMap); // empty map Optional.empty flatMap Optional[House.Door(type=null)]
    // map, flatMap returns a container with a value
    Optional<House.Door> doorOptional = houseOptionalHasDoor.map(House::getDoor);
    Optional<House.Door> doorFromFlatMapOptional = houseOptionalHasDoor.flatMap(item -> Optional.of(new House.Door()));
    System.out.println("has door map " + doorOptional + " flatMap " + doorFromFlatMapOptional); // has door map Optional[House.Door(type=null)] flatMap Optional[House.Door(type=null)]
    // orElseThrow
    houseOptional.orElseThrow(() -> new RuntimeException()); // House(door=null)
    houseNullOptional.orElseThrow(() -> new RuntimeException()); // java.lang.RuntimeException
}
Copy the code

Optional solve the NPE

So after Optional, let’s go back to our original example where we used Optional to handle the empty problem, and add the getOptionalDoorTypeName method to House

public String getOptionalDoorTypeName(a) {
    // Stuff the current door into the Optional container
    Optional<Door> door = Optional.ofNullable(this.door);
    // Stuff the type into the Optional container
    Optional<Type> type = Optional.ofNullable(door.orElse(new Door()).getType());
    String name = type.orElse(new Type()).getName();
    return Objects.isNull(name) ?  "Unknown type" : name;
}
/ / test
public void testOptionalOptimizeNPE(a){
    House house = new House();
    System.out.println(house.getOptionalDoorTypeName()); // Unknown type
    // Set the type name
    House.Type type = new House.Type();
    type.setName("Glass");
    House.Door door = new House.Door();
    door.setType(type);
    house.setDoor(door);
    System.out.println(house.getOptionalDoorTypeName()); / / glass
}
Copy the code

A more elegant way to write it

The above solution is based on adding a getOptionalDoorTypeName method to House. The internal implementation of the method still looks bloated, so it is recommended to handle the property itself in the class. The code is as follows:

Data
public class OptionalHouse {

    private Optional<Door> door = Optional.empty();

    public String getDoorTypeName(a) {
        String name = door.orElse(new Door()).getType().orElse(new Type()).getName();
        return Objects.isNull(name) ?  "Unknown type" : name;
    }

    @Data
    public static class door {
        private Optional<Type> type = Optional.empty();
    }

    @Data
    public static class Type {
        privateString name; }}Copy the code

The source code

  • 👉 source can be accessed here

conclusion

  • This chapter introduces Optional. Optional is a container object that supports holding generic values. The value can be null or non-null.
  • Optional Creates Optional objects using static methods. Some object methods, such as filter and map, are similar to Stream.
  • Using Optional can effectively reduce if nesting and increase code readability.

Related articles

👉 [Learn again series]

The last

  • Thank you for your patience to see the end, if you feel this article is helpful, please give aPraise 👍orFocus on ➕;
  • Due to my limited technology, the article and code may be wrong, I hope you comment pointed out, very grateful 🙏;
  • At the same time, I also welcome you to discuss learning front-end, Java knowledge, volume and progress together.