This is the fourth day of my participation in the November Gwen Challenge. See details: The last Gwen Challenge 2021.

What are the problems with NULL?

1) NullPointerException is the most typical exception in Java program development.

2) It makes your code swell. It fills your code with deeply nested null checks.

3) It is meaningless by itself.

4) It undermines the Java philosophy. Java tries to keep programmers from being aware of Pointers, with one exception: null Pointers.

5) It cracks a hole in Java’s type system. Null is not of any type, which means it can be assigned to any variable that references a type.

For example, if you have a car, is it insured? Let’s get the name of the insurance from the object of the car. The code is as follows

import lombok.Data;

/ * * *@description: TestOptional *@author: weirx *@date: 2021/10/26 14:26 *@version: 3.0 * /
public class TestOptional {

    @Data
    static class Car{

        private Insurance insurance;

        private String name;
    }

    @Data
    static class Insurance{

        private String name;
    }
    
    public static void main(String[] args) {
        Car car = newCar(); car.getInsurance().getName(); }}Copy the code

Results:

Exception in thread "main" java.lang.NullPointerException
	at com.cloud.bssp.java8.Optional.TestOptional.main(TestOptional.java:31)
Copy the code

As shown above, we hate the null pointer exception, how to prevent? Nothing more than adding non-null judgments:

car.getInsurance() == null ? null : car.getInsurance().getName();
Copy the code

Although the above code solves the null pointer problem, it increases the complexity and readability of the code.

Second, Optional class introduction

Taking inspiration from Haskell and Scala, a new class java.util.Optional was introduced in Java 8. This is a class that encapsulates Optional values.

In the null pointer example above, if you do not know whether the car is insured or not, you should not declare the Insurance as Insurance, but as Optional.

The Optional class simply wraps the class when the variable exists. 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.

With Optional we can declare something like this:

    static class Car {

        private Optional<Insurance> insuranceOptional;

        private String name;
    }
Copy the code

Semantically, declaring your class with Optional makes it very clear whether the missing variable value is a structural problem, a flaw in your algorithm, or a problem in your data.

C. Optional use

3.1 Creating an Optional Object

        // 1, declare an empty Optional
        Optional<Car> optional1 = Optional.empty();

        // create Optional from a non-null value. If a null is passed, a null pointer exception will be raised
        Optional<Car> optional2 = Optional.of(new Car());

        // Optional that accepts NULL: Using the static factory method optional. ofNullable, you can create an Optional that allows NULL values
        // If car is null, the resulting Optional object is empty.
        Optional<Car> optional3 = Optional.ofNullable(null);
Copy the code

3.2 Extract and convert values from Optional objects using Map

Optional provides a map method that works like this:

        Optional<Car> optionalCar = Optional.ofNullable(car);
        Optional<String> optionalName = optionalCar.map(Car::getName);
Copy the code

This is similar to the previous article when we studied map in Stream.

So if we want to get the name of the insurance how do we get it?

        Car car = new Car();
        car.setInsuranceOptional(Optional.empty());
        Optional<Car> optionalCar = Optional.ofNullable(car);
        optionalCar.map(Car::getInsuranceOptional).map(Insurance::getName);
Copy the code

The code above will not compile. GetInsuranceOptional returns an Optional object, and the map operation becomes getName on an Optional<Optional> object, which is illegal.

3.3 Linking Optional objects using flatMap

To solve the previous problem, at this point we can use the flatMap method, which has the same effect as the flatMap in the Stream. What we’re going to do here is merge two layers of Optional into one Optional:

        Car car = new Car();
        car.setInsuranceOptional(Optional.empty());
        Optional<Car> optionalCar = Optional.ofNullable(car);
        optionalCar.flatMap(Car::getInsuranceOptional).map(Insurance::getName);
Copy the code

Insurance is the empty Optional option in the car. Running the above code will not raise the null pointer exception, but we still need to handle it using orElse(), as shown below:

        Car car = new Car();
        car.setInsuranceOptional(Optional.empty());
        Optional<Car> optionalCar = Optional.ofNullable(car);
        String unknown = optionalCar.flatMap(Car::getInsuranceOptional).map(Insurance::getName).orElse("unknown"); System.out.println(unknown); ----------- Command output --------------- unknownCopy the code

3.4 Reading the value in the Optional object

3.4.1 track the get ()

Get () is the simplest and least secure of these methods. If the variable exists, it returns the value of the encapsulated variable directly, otherwise a NoSuchElementException is thrown.

Unless you are absolutely sure that the Optional variable contains a value, using this method is a pretty bad idea.

Furthermore, this approach doesn’t represent much of an improvement over even nested NULL checks.

        Car car = newCar(); car.getInsuranceOptional().get(); -------- ----------- Exception in thread"main" java.util.NoSuchElementException: No value present
	at java.util.Optional.get(Optional.java:135)
	at com.cloud.bssp.java8.Optional.TestOptional.main(TestOptional.java:36)
Copy the code

Other 3.4.2 orElse (T)

OrElse (T Other) is the method mentioned in the previous example. It allows you to provide a default value for Optional objects that do not contain a value.

        Car car = new Car();
        car.setInsuranceOptional(Optional.empty());
        Optional<Car> optionalCar = Optional.ofNullable(car);
        String unknown = optionalCar.flatMap(Car::getInsuranceOptional).map(Insurance::getName).orElse("unknown"); System.out.println(unknown); ----------- Command output --------------- unknownCopy the code

Rule 3.4.3 orElseGet: Supplier <? extends T> other)

Deferred call version of the orElse method.

The Supplier method is called only if the Optional object does not contain a value.

You can also do this if you need to do something else to create a default value, or if you need to be pretty sure that a method will only be called when Optional is empty (there are strict restrictions on this).

    public static String test(a) {
        System.out.println("this car has no insurance");
        return "unknown";
    }

        Car car = newCar(); car.setInsuranceOptional(Optional.empty()); Optional<Car> optionalCar = Optional.ofNullable(car); String unknown = optionalCar.flatMap(Car::getInsuranceOptional).map(Insurance::getName).orElseGet(TestOptional::test); System.out.println(unknown); Output -- -- -- -- -- -- -- -- -- -- -- -- -- -- --this car has no insurance
unknown
Copy the code

3.4.4 orElseThrow: Supplier <? extends X> exceptionSupplier)

Much like the orElseGet method, they all throw an exception when the Optional object is empty, but with orElseThrow you can customize the type of exception you want to throw.

    static class MyException extends RuntimeException{

    }

        Car car = new Car();
        car.setInsuranceOptional(Optional.empty());
        Optional<Car> optionalCar = Optional.ofNullable(car);
        String unknown = optionalCar.flatMap(Car::getInsuranceOptional).map(Insurance::getName).orElseThrow(MyException::new); System.out.println(unknown); ------- ----------- Exception in thread"main" com.cloud.bssp.java8.Optional.TestOptional$MyException
	at java.util.Optional.orElseThrow(Optional.java:290)
	at com.cloud.bssp.java8.Optional.TestOptional.main(TestOptional.java:42)
Copy the code

3.4.5 ifPresent (Consumer <? super T>)

Can execute a method passed in as an argument in the presence of a variable value, otherwise nothing is done.

    static void addName(String name){
        System.out.println("the insurance is : " + name);
    }

        Car car = new Car();
        Insurance insurance = new Insurance();
        insurance.setName("Car insurance"); car.setInsuranceOptional(Optional.of(insurance)); Optional<Car> optionalCar = Optional.ofNullable(car); optionalCar.flatMap(Car::getInsuranceOptional).map(Insurance::getName).ifPresent(TestOptional::addName); -- -- -- -- -- -- -- -- -- -- -- -- -- -- output -- -- -- -- -- -- -- -- -- -- -- -- -- -- the insurance is: car insuranceCopy the code

3.4.6 isPresent

Return true if it exists, false if it does not.

        Car car = new Car();
        car.setInsuranceOptional(Optional.empty());
        System.out.println(car.getInsuranceOptional().isPresent());

        Insurance insurance = new Insurance();
        insurance.setName("Car insurance"); car.setInsuranceOptional(Optional.of(insurance)); System.out.println(car.getInsuranceOptional().isPresent()); -- -- -- -- -- -- -- -- -- -- -- -- -- -- output -- -- -- -- -- -- -- -- -- -- -- -- -- --false
true
Copy the code

3.4.7 filter (Predicate <? super T> predicate)

The filter method takes a predicate as an argument. The filter method returns the value of the Optional object if it exists and matches the predicate condition. Otherwise it returns an empty Optional object.

        Car car = new Car();
        Insurance insurance = new Insurance();
        insurance.setName("Car insurance");
        car.setInsuranceOptional(Optional.of(insurance));
        Optional<Car> optionalCar = Optional.ofNullable(car);
        Optional<String> s = optionalCar.flatMap(Car::getInsuranceOptional).map(Insurance::getName).filter("Car insurance"::equals); System.out.println(s.get()); ------------ output ----------- auto insuranceCopy the code

Hey, guys, you got something. Give it a thumbs up