101.【Using Optional, colleagues say they don’t understand it!】


Reference: this article

(1), Optional

1. The concept of Optional

java.util.Optional is a new class introduced in java8,It can model possible missing values ​​instead of directly assigning null to variables

It is used to standardize the API we developed to make its semantics clearer. Objects decorated with Optional indicate that the object may be null.Avoids the problem of null pointers to a certain extent

Why use Optional?

The most annoying thing in java is nullpoint. When encountering a null pointer, an error will be thrown and an Exception will be thrown. Then it is necessary to check which object is empty line by line, which will bring a lot of unnecessary energy consumption . Throwing an NPE error is not a user operation error, but It is a developer's mistake and should be avoided, so you can only add non-null checks in each method, which is relatively poor in readability and maintainability.

2. Optional class usage

The Javadoc description of the Optional class is as follows: This is a container object that can be null.
The isPresent() method returns true if the value exists,Calling the get() method will return the object.
If the value does not exist, the isPresent() method returns false,Calling the get() method will cause NPE

The method of creating Optional class object:

  • Optional.of(T t) : Create an Optional instance,t must be non-null
  • Optional.empty() : create aan empty Optional instance
  • Optional.ofNullable(T t):t can be null

1. Create an empty

	//使用Optional.empty()方法创建一个空的Car类型的Optional对象。
  Optional<Student> optionalCar = Optional.empty();

2. Create an Optional with a non-null value. If the car is null, a null pointer exception will be thrown directly (refer to the picture above).

 Car car = new Car();
 Optional<Car> car1 = Optional.of(car);

3. Create an Optional that can be null. This method supports the car being null, but an exception will be thrown where the car is used, but it is not a null pointer exception.

   Car car = new Car();
   Optional<Car> car2 = Optional.ofNullable(car);

Determine whether the Optional container contains objects:

  • boolean isPresent() : Determine whether to contain the object
  • void ifPresent(Consumer<? super T> consumer) :If there is a value, the implementation code of the Consumer interface is executed, and the value is passed to it as a parameter

Get the object of the Optional container:

  • T get(): If the calling object contains a value, returns that value,Otherwise throw an exception
  • T orElse(T other) : returns a value if there is one,Otherwise return the specified other object
  • T orElseGet(Supplier<? extends T> other) : returns a value if there is one,Otherwise return the object provided by the Supplier interface implementation
  • T orElseThrow(Supplier<? extends X> exceptionSupplier) : return value if there is one,Otherwise throw the exception provided by the Supplier interface implementation

filter:

  • Optional filter(Predicate<? super predicate): If the value exists, and the value matches the given predicate, return an Optional to describe the value,Otherwise return an empty Optional

map

  • Optional map(Function<? super T,? extends U> mapper): If there is a value,Then call the mapping function to get the return value. If the return value is not null, create an Optional containing the return value of the map as the return value of the map method, otherwise return an empty Optional.
  • Optional flatMap(Function<? super T, Optional > mapper): If the value exists,Executes the provided mapping function call on the value, returns a value of type Optional, otherwise returns an empty Optional object

3. Create the Optional class

   @Test
    public void testOption() {
    
    
        // 1.声明一个空Option
        Optional<Object> empty = Optional.empty();
        // 2. 根据一个非空值创建Optional
        Student student = new Student();
        Optional<Object> of = Optional.of(student);
        // 3. 根据可接受的null 进行创建
        Student student1=null;
        Optional<Student> student11 = Optional.ofNullable(student1);
    }

insert image description here

4. Determine whether the Optional container contains objects

isPresent does not take parameters to determine whether it is empty, and ifPresent can choose to have an instance of a consumption function. ( isPresent和ifPresent一个是 is 一个是 if 注意一下哈)

    @Test
    public void testOption() {
    
    

        // 1. isPresent是否有值

        Student student = new Student("吉士先生",21,90);
        Optional<Student> student1 = Optional.ofNullable(student);
        if (student1.isPresent()){
    
    
            System.out.println(student.getName());
        }

        // 2. ifPresent有一个Customer匿名内部类

        student1.ifPresent(new Consumer<Student>() {
    
    
            @Override
            public void accept(Student student) {
    
    
                System.out.println(student.getName());
            }
        });

        // 3. 匿名内部类,进行lambda处理

        student1.ifPresent(s-> System.out.println(s.getName()));

    }

insert image description here

5. Get the object of the Optional container

    @Test
    public void testOption() throws Exception {
    
    

        Student student = null;

        Optional<Student> student1 = Optional.ofNullable(student);
        // 使用get一定要注意,假如student对象为空,get是会报错的
        // java.util.NoSuchElementException: No value present
        Student student3 = student1.get();

        // 当student为空的时候,返回我们新建的这个对象,有点像三目运算的感觉
        Student student2 = student1.orElse(new Student("李明", 20, 16));

        // orElseGet就是当student为空的时候,返回通过Supplier供应商匿名内部类 创建的对象
        student1.orElseGet(new Supplier<Student>() {
    
    
            @Override
            public Student get() {
    
    
                return new Student("李明2", 21, 17);
            }
        });

        //利用Lambda 实现供应商匿名内部类   {}和return 可以被省略
        student1.orElseGet(()->new Student("李明3", 20, 16));
        

        // orElseThrow就是当student为空的时候,可以抛出我们指定的异常
        student1.orElseThrow(()->new Exception("抛出我们指定的异常"));
    }

6. Filter

    @Test
    public void testOption() throws Exception {
    
    

        Student student = new Student("吉士先生",3,20);
        Optional<Student> os1 = Optional.ofNullable(student);
        os1.filter(new Predicate<Student>() {
    
      // 进行过滤
            @Override
            public boolean test(Student student) {
    
    
                return student.getName().equals("吉士先生");
            }
        }).ifPresent(new Consumer<Student>() {
    
      //假如说存在值
            @Override
            public void accept(Student student) {
    
    
                System.out.println("Ok");
            }
        });

        os1.filter((s)->s.getName().equals("吉士先生")).ifPresent(d-> System.out.println("OK"));
    }

insert image description here

7. Mapping

Map 源码信息

    public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    
    
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
    
    
            return Optional.ofNullable(mapper.apply(value));
        }
    }
    @Test
    public void testOption() throws Exception {
    
    

        Student student = new Student("吉士先生",3,20);
        Optional<Student> os1 = Optional.ofNullable(student);
        os1.map(new Function<Student, Object>() {
    
      //如果不为空,那么就+1岁
            @Override
            public Object apply(Student student) {
    
    
                student.setAge(student.getAge()+1);
                return student;
            }
        });
        System.out.println(student);
        os1.map(s->{
    
    s.setAge(s.getAge()+1);return s;});
        System.out.println(student);

    }

insert image description here
To be honest, this map is very confusing for those who are not very proficient in lambda.

The map here is actually the Function function used. The Function function has two parameters. The first is the input data type, and the second is the return data type. The function of the Function function is to pass in an object and then return an object. The type of the returned object can be set by yourself.

T is the generic data type representing the instance, that is, the input parameter of whoever calls must be the same as the generic data type of the caller.
U has the final say, what data type to return after calling map, then U will set what

源码

public static Optional<Integer> stringToInt(String s) {
    
    
     try {
    
    
         return Optional.of(Integer.parseInt(s));
     } catch (NumberFormatException e) {
    
    
         e.printStackTrace();
         return Optional.empty();
     }
 }
Optional.ofNullable(props.getProperty(name))
        .flatMap(OptionalUtils::stringToInt)
        .filter(i -> i>0)
        .orElse(0);

(2), anonymous inner class

1. What is an anonymous inner class?

We all know that Lambda is an anonymous function, using Lambda can help us simplifyanonymous inner classHowever, anonymous inner classes are not used very much in actual development, and many people don’t have a deep impression of them, so it is necessary for us to understand anonymous inner classes first.

What is an anonymous inner class.

An anonymous inner class is a nested class without a name. It is one of the ways Java defines classes.

Why use anonymous inner classes?

In actual development, we often encounter such a situation: a certain implementation of an interface/class method will only be executed once in the program, but in order to use it, we need to create its implementation class/subclass to implement/ rewrite. At this time, you can use the anonymous inner class method,There is no need to create new classes, reducing code redundancy

Can anonymous inner classes only be used on interfaces?

no. Anonymous inner classes can be used inconcrete class, abstract class, interfaceon, and the methodThe number is not required

2. Custom anonymous inner class implementation

Suppose there is currently an interface with only one method :

package com.example.springboot01hello.dao;

public interface interface1 {
    
    
    void show();
}

In order to use the show method of this interface, we need to create an implementation class and write the specific implementation of the show method

package com.example.springboot01hello.dao;

public class interfaceImpl implements interface1{
    
    
    @Override
    public void show() {
    
    
        System.out.println("我是实现类");
    }
}

If the implementation class InterfaceImpl is only used once in the whole process , it would be too troublesome to create a class for this use. We need a way to help us out of this predicament.Anonymous inner classes can solve this problem very well

We use anonymous inner class

    @Test
    public void test3(){
    
    
        interface1 interface1 = new interface1() {
    
      //实列化一个接口
            @Override
            public void show() {
    
    
                System.out.println("这里是一个匿名内部类");
            }
        };
        interface1.show();
    }

Note: Anonymous inner classes cannot have ordinary static variable declarations, only static constants.

3. Thread anonymous inner class implementation

Usually, we are also used toanonymous inner classCreate and start threads by

Through the following example, you will find that Thread is a common class and can be created with an anonymous inner class, and Runnable is an interface that can also be created with an anonymous inner class.

    @Test
    public void test3(){
    
    
        new Thread(){
    
      //线程实现匿名内部类, new Thread(){Ctrl+H}
            @Override
            public void run() {
    
    
                System.out.println(Thread.currentThread().getName()+"创建线程1");
            }
        }.start(); //开启线程


        Runnable runnable = new Runnable() {
    
     // 利用Runnable开启线程
            @Override
            public void run() {
    
    
                System.out.println(Thread.currentThread().getName() + "创建线程2");
            }
        };
        new Thread(runnable).start(); //开启线程
    }

insert image description here

(3), functional (Function) interface

1. Overview of functional interface

What is a Functional Interface

The functional interface isinterface with only one method,at the same time,Only functional interfaces can use lambda expressions

在java.util.function包下定义了Java 8 的丰富的函数式接口

Is lambda in Java functional programming?

In functional programming languages, the type of a lambda expression is a function.In Java8, Lambda expressions are objects, not functions, they must be attached to a special class of object types—functional interfaces.

2. Classic functional interface

The Runnable interface is a typical functional interface, which is also used when creating threads above. It can be instantiated in the form of an anonymous inner class.
Runable是一个典型的函数式接口

@FunctionalInterface
public interface Runnable {
    
    
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

new Thread(()-> System.out.println(Thread.currentThread().getId()+"<-当前的线程名字")).start();

        Runnable runnable = () -> {
    
    
            System.out.println(Thread.currentThread().getId());
        };

3. Custom functional interface

package com.example.springboot01hello.dao;

@FunctionalInterface //表明我们这里是函数式接口,可设可不设。设置的话会提升性能
public interface interface1 {
    
    
    void show();
}

Generics are used in functional interfaces:

package com.example.springboot01hello.dao;

@FunctionalInterface //表明我们这里是函数式接口,可设可不设。设置的话会提升性能
public interface interface1<T> {
    
    
    public  T show(T t);
}

4. @FunctionlInterface usage

  1. This annotation can only be marked on the interface with " one and only one method ", indicating a functional interface.
  2. This annotation is not necessary . If an interface conforms to the definition of "functional programming", adding or not adding this annotation has no effect. Adding this annotation can better allow the compiler to check,If you write a non-functional interface, but add @Functionallnterface, the compiler will report an error
  3. Using this annotation on a functional interface, the javadoc will also include a statement that the interface is a functional interface

5. Four core functional interfaces

特别重要!!!

insert image description here

6. Other functional interfaces

insert image description here

(4), Lambda expression

1. Overview of Lambda expressions

Lambda is an anonymous function. We can understand a Lambda expression as a piece of code that can be passed (pass code like data).Use it to write more concise and flexible code

The Relationship Between Lambda Expressions and Functional Interfaces

A lambda expression is an instance of a functional interface(Note that it is an instance, Object a = new Object(), this a is just a reference variable, and new Object is an instance).As long as an object is an instance of a functional interface, then the object can be represented by a Lambda expression

The Relationship Between Lambda Expressions and Anonymous Inner Classes

Functional interfaces can use anonymous inner classes to create instances , and lambdas can simplify the use of anonymous inner classes to create .

Note: The prerequisite for using lambda to simplify anonymous inner classes is that the interface must be a functional interface. However, creating an instance of an anonymous inner class does not necessarily have to be a functional interface, or even an interface, and it can also be an ordinary class.
insert image description here

The three relationships of anonymous inner classes, functional interfaces, and lambda expressions must be clarified.

2. Lambda syntax

Lambda expressions: A new syntax element and operator introduced in the Java 8 language. this operator

is "->", the operator is called the Lambda operator or the arrow operator. It splits Lambda into two parts:

  1. left side: Specifies the required lambda expressionparameter list
  2. Right: Specifies the Lambda body, which is the implementation logic of the abstract method, that is, LambdaexpressionThe function to perform.

3. Anonymous inner class conversion Lambda

Conversion example 1 from anonymous class to Lambda:

Through the following example, we can find a problem: using an anonymous inner class, it can be created without a variable reference, but lambda cannot, it must have a variable reference. This variable reference can be a direct variable reference or a parameter passing within a method.A lambda expression is an instance of a functional interface

注意俩字 “实列”!!!!!!

If there are no variable references such as:

() -> System.out.println("我是一个函数式"); Only this will definitely not work,Need to rely on the previous TestInterface variable reference to do type inference.

    @Test
    public void test3() {
    
    

        interface1 interface0 = new interface1() {
    
    
            @Override
            public void show() {
    
    
                System.out.println("我是匿名内部类函数");
            }
        };
        interface0.show();

        interface1 interface2 = () -> {
    
    
            System.out.println("我是Lambda表达式");
        };
        interface2.show();
    }

insert image description here

4. Anonymous Inner Class Conversion Lambda 2

Through the following example, you will find that he is actually constantly optimizing, so that our developers can write as little code as possible. How did he omit it step by step? Actually this isJava syntactic sugar

    @Test
    public void test3() {
    
    
        // 1.匿名内部类创建线程

        Runnable runnable = new Runnable() {
    
     // 利用Runnable开启线程
            @Override
            public void run() {
    
    
                System.out.println(Thread.currentThread().getName() + "创建线程1");
            }
        };
        new Thread(runnable).start(); //开启线程

        // 2.省去Runnable变量,等同于上方
        new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                System.out.println(Thread.currentThread().getName() + "创建线程2");
            }
        }).start(); //开启线程

        // 3.使用Lambda表达式,实现多线程,省去了new Runnable和重写的方法名字
        new Thread(() -> {
    
    
            System.out.println(Thread.currentThread().getName() + "创建线程3");
        }).start();

        // 4.优化Lambda,去掉大括号
        new Thread(() ->  System.out.println(Thread.currentThread().getName() + "创建线程3")).start();
    }

insert image description here

5.Lambda syntax format

Code Description: Use Lambda expressions.The general format is () -> 0, if there is only one line of code in 0, then 0 can be omitted.
->The () on the left indicates the parameter list, 如果有形参,则在()中添加形参,->右边0表示具体逻辑. if method bodyThe return value is void, you can even not write any logic in 0 (of course, it must be combined with the scene).return value if any, you need to write specific logic and return the processed value.

insert image description here
insert image description here

6. Type inference

There is no need to specify the type in the Lambda expression, and the program can still be compiled, because javac infers it from the compiler based on the context of the program. This is called "type inference".
insert image description here
To put it bluntly, using the characteristics of generic classes can directly allow us to omit types.

Code example:

接口

package com.example.springboot01hello.dao;

@FunctionalInterface //表明我们这里是函数式接口,可设可不设。设置的话会提升性能
public interface interface1<String> {
    
    
    void show(java.lang.String str);
}

测试

    @Test
    public void test3() {
    
    

        // 匿名内部类创建 带有泛型参数的
        interface1<String> interface0 = new interface1<String>() {
    
    
            @Override
            public void show(String str) {
    
    
                System.out.println(str);
            }
        };
        interface0.show("hello");
        // 使用lambda进行改造
        interface1<String> stringinterface1 = (String str) -> {
    
    
            System.out.println(str);
        };
        stringinterface1.show("world");
        // 使用lambda进行再次优化, 去掉类型和()与{}
        interface1<String> stringinterface3 = str -> System.out.println(str);

        stringinterface3.show("jsxs");

    }

insert image description here

7. Parameter passing

We all know that lambda is an instance. When using lambda, there must be variable references . In addition to variable references, it is also possible to pass parameters in methods like this

(1). Code Example 1

@FunctionalInterface
interface MyFunc<T> {
    
    
    T getValue(T t);
}

public class Test {
    
    
    public static void main(String[] args) {
    
    
        
        // str的小括号是可以去掉的
        String abc = toUpperString((str) -> str.toUpperCase(), "abc");
        // String abc = toUpperString(str -> str.toUpperCase(), "abc");
        System.out.println(abc);
    }

    public static String toUpperString(MyFunc<String> consumer, String str) {
    
    
        return consumer.getValue(str);
    }
}

To pass a Lambda expression as a parameter, the type of the parameter receiving the Lambda expression must be the type of the functional interface compatible with the Lambda expression.

(2). Code example 2

Many Java uses lambdas based on parameter passing, such as forEach of collections.
insert image description here

import java.util.Arrays;
import java.util.List;

public class jsxs1 {
    
    
    public static void main(String[] args) {
    
    
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        list.forEach(b-> System.out.println(b));
    }
}

insert image description here

8. Quote

(1). Method reference

What is a method reference?

A method reference is also an instance of a functional interface, pointing to a method by its name,Can be considered a syntactic sugar for Lambda expressions

When to use method references?

When the operation to be passed to the Lambda body has an implementation method, you can use the method reference!

There are three main use cases:

  1. object::instance method name
  2. class::static method-name
  3. class::instance method-name

Format: Use the operator "::" to separate the class (or object) from the method name.

ClassName::methodName

Requirements

implements the abstract method of the interfaceParameter list and return type, must be the same as the method referenced by the methodThe parameter list and return value type are consistent

Code example one:

Consumer consumption function, that is, only input parameters, no return value.

import java.util.function.Consumer;

public class jsxs1 {
    
    
    public static void main(String[] args) {
    
    
        // 消费者内部匿名类
        Consumer consumer = new Consumer() {
    
    
            @Override
            public void accept(Object o) {
    
    
                System.out.println("消费者接口");
            }
        };

        // 创建lamda
        Consumer consumer1 = (x) -> System.out.println(x);

        consumer1.accept("hello");
        // 方法引用
        Consumer consumer2=System.out::print;
        consumer2.accept("world");
    }
}

insert image description here

Code example 2:
Comparator is a comparator function with two input parameters and one return value.

import java.util.Comparator;

public class jsxs1 {
    
    
    public static void main(String[] args) {
    
    

        // 1.匿名内部类创建,<Integer>这个泛型一定要带,不然下面就只能是object
        new Comparator<Integer>(){
    
    
            @Override
            public int compare(Integer o1, Integer o2) {
    
    
                return Integer.compare(o1,o2);
            }
        };

        // lambda方式创建,<Integer>这个泛型一定要带,不然报错
        Comparator<Integer> comparator1 = (a, b) -> Integer.compare(a, b);
        System.out.println(comparator1.compare(1, 2));
        // 方法引用,<Integer>这个泛型一定要带,不然报错
        Comparator<Integer> compare = Integer::compare;
        System.out.println(compare.compare(6, 4));  // 判断前面的值是否大于后面的值
    }
}

insert image description here

Code example three:

BiPredicate is a decision function with two input parameters and a Boolean return value.

import java.util.Comparator;
import java.util.function.BiPredicate;

public class jsxs1 {
    
    
    public static void main(String[] args) {
    
    

        // 这里的<String, String>类型不能丢,因为下面用的是String,如果不声明类型就是Object
        BiPredicate biPredicate = new BiPredicate<String, String>() {
    
    
            @Override
            public boolean test(String o, String o2) {
    
    
                return o.equals(o2);
            }
        };
        
        // 这里变量没有声明类型,那么就是Object,equals也是调用的Object的
        BiPredicate biPredicate1 = (a, b) -> a.equals(b);

        // 这里类型必须要写,因为后面写明了调用String的equals
        BiPredicate<String, String> biPredicate2 = String::equals;
    }
}

(2).Constructor reference

Format: ClassName::new

Combined with a functional interface, it is automatically compatible with methods in the functional interface.

The constructor parameter list is required to be consistent with the parameter list of the abstract method in the interface! And the return value of the method is the object of the class corresponding to the constructor.

import java.util.function.Function;

class Teacher {
    
    
    private String name;

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Teacher(String name) {
    
    
        this.name = name;
    }
}

public class Test4 {
    
    
    public static void main(String[] args) {
    
    
        // 匿名内部类
        Function function = new Function<String, Teacher>() {
    
    
            @Override
            public Teacher apply(String name) {
    
    
                return new Teacher(name);
            }
        };

        // lambda
        Function<String, Teacher> function1 = (a) -> new Teacher(a);

        // 构造器引用
        Function<String, Teacher> function2 = Teacher::new;
    }
}

(3). Array reference

Format:type[] :: new

public static void main(String[] args) {
    
    
    // 匿名内部类
    Function function = new Function<Integer, Integer[]>() {
    
    
        @Override
        public Integer[] apply(Integer x) {
    
    
            return new Integer[x];
        }
    };

    // lambda
    Function<Integer, Integer[]> function1 = a -> new Integer[a];

    // 数组引用
    Function<Integer, Integer[]> function2 = Integer[]::new;
}

Guess you like

Origin blog.csdn.net/qq_69683957/article/details/129583866