Stream流-详细

在这里插入图片描述

java8新特性介绍:

在这里插入图片描述

速度更快是因为hashmap等结构进行了改变升级,换成了数组+链表+红黑树,查询效率等大大提高。

在这里插入图片描述

jdk1.8内存结构的更新:
在这里插入图片描述

在这里插入图片描述

lamda表达式的介绍和使用:

lamda语法:
在这里插入图片描述

在这里插入图片描述

需求一:
在这里插入图片描述

需求二:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

package com.fan.yygh.hosp;

import org.junit.jupiter.api.Test;

public class lamdaTest {
    @Test
    public void test01(){
       
        Runnable runnable = () -> {
            System.out.println("Hello ,lamda");
        };
        runnable.run();
    }
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

总结:左右遇一括号省,左侧推断类型省,能省则省
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

使用:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

将lamda表达式像所有的数据一样来回传递。
自定义函数接口:

@FunctionalInterface
interface myFunction<T,R> {
    //有2个参数需要处理
    public R getValue(T t1,T t2);
}

package com.fan.yygh.hosp;

import org.junit.jupiter.api.Test;

import java.util.Comparator;
import java.util.function.Consumer;

public class lamdaTest {
    @Test//1.无参数无返回值的lamda表达式
    public void test01(){
        Runnable runnable = () -> {
            System.out.println("Hello ,lamda");
        };
        runnable.run();
    }
    @Test//2.有一个参数无返回值的lamda表达式
    public void test02(){
        Consumer<String> consumer = (x) -> System.out.println(x);
        consumer.accept("测试");
    }
    @Test//3.有2个参数有返回值的lamda表达式
    public void test03(){
        Comparator<Integer> comparator = (x, y) ->{
            System.out.println("函数式接口");
            return Integer.compare(1,2);
        };
    }
    @Test//3.有2个参数有返回值的lamda表达式
    public void test04(){
        Comparator<Integer> comparator = (x, y) -> Integer.compare(1,2);
        };

    //练习题最后一个答案:
    @Test
    public void test05(){
        TestLamd testLamd = new TestLamd();
        testLamd.sum(100L,200L,(A,B) -> {
            return A+B;
        });
        testLamd.sum(100l,200l,(a,b) -> a*b );
    }
    private class TestLamd {
        public void sum (Long a,Long b,myFunction<Long,Long> myFunction){
            System.out.println(myFunction.getValue(a,b));
        }
    }
    /*========end========*/
}

函数式接口:

1.Consumer<T> :消费型接口
void accept(T t);


2.Supplier:供给型接口
T get();

3.Function<T,R>:函数型接口
R apply(T t);

4.Predicate<T>:断言型接口
boolean test(T t);

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

lamda表达式的-》后的用于实现函数是接口的具体实现;

在这里插入图片描述

在这里插入图片描述

方法引用:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

构造器引用:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

stream流

1.什么是Stream流?

在Java 8中,得益于Lambda所带来的函数式编程, 引入了一个全新的Stream流概念。

目的:用于简化集合和数组操作的API。

2.Stream流式思想的核心:

1、先得到集合或者数组的Stream流(就是一根传送带)
2、把元素放上去
3、然后就用这个Stream流简化的API来方便的操作元素。

3.Stream流的作用是什么,结合了什么技术?
简化集合、数组操作的API。结合了Lambda表达式。

4.说说Stream流的思想和使用步骤。
1、先得到集合或者数组的Stream流(就是一根传送带)。
2、把元素放上去。
3、然后就用这个Stream流简化的API来方便的操作元素。

在这里插入图片描述

在这里插入图片描述

Stream流的获取
Stream流的操作的三个步骤:
1、获取Stream流——>创建一条流水线,并把数据放到流水线上准备进行操作.
2、中间方法——>流水线上的操作。一次操作完毕之后,还可以继续进行其他操作.
3、终结方法——>一个Stream流只能有一个终结方法,是流水线上的最后一个操作.

注:Stream操作集合或者数组的第一步是先得到Stream流,然后才能使用流的功能。

在这里插入图片描述

Stream流的创建:

常见的创建流的4种方式:

1、通过 java.util.Collection.stream() 方法用集合创建流

List<String> list = Arrays.asList("a", "b", "c");
// 创建一个顺序流
Stream<String> stream = list.stream();
// 创建一个并行流
Stream<String> parallelStream = list.parallelStream();

2、使用java.util.Arrays.stream(T[] array)方法用数组创建流

 //  数组获取流的方式
Stream<String> namesStream = Arrays.stream(数组名array);

int[] array={1,3,5,6,8};
IntStream stream = Arrays.stream(array);

3、通过Stream类中的静态方法of()来创建流

 Stream<String> stream3 = Stream.of("a", "b", "c");
 Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);

4、由函数生成流—创建无限流:Stream.iterate和Stream.generate

Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
stream2.forEach(System.out::println);

Stream<Double> stream3 = Stream.generate(Math::random).limit(3);
stream3.forEach(System.out::println);

在这里插入图片描述

@Test //流的创建
    public void test01(){
        //1.通过集合Collections集合提供的stream()或者parallelStream()
        ArrayList<Integer> list = new ArrayList<Integer>( Arrays.asList(1, 2, 3, 4));
        Stream<Integer> stream1 = list.stream();
        //Stream<Integer> parallelStream = list.parallelStream();

        //2.数组获取流的方式,通过Arrays中的静态方法stream()获取数组流
        int[] arr = new int[]{1,2,3,4};
        IntStream stream2 = Arrays.stream(arr);
        stream2.filter((x) -> x>2)
                .forEach(System.out::println);

        //3.通过Stream类中的静态方法of()来获取流
        Stream<String> stream3 = Stream.of("a", "b", "c");
        //4.由函数生成流---创建无限流:Stream.iterate和Stream.generate:

        // 4.1,iterate:从0开始,一直在原来数的基础上增加2来生产一个流
        /*static <T> Stream<T> iterate​(T seed, UnaryOperator一元运算<T> f)

        static <T> Stream<T> iterate​(T seed, Predicate<? super T> hasNext,
        UnaryOperator<T> next)
        */
        Stream.iterate(0,(x)->x+2)
                .limit(3)
                .forEach(System.out::println);
        //4.2,static <T> Stream<T> generate​(Supplier<? extends T> s)
        // generate​该方法主要用于生成一个无限连续的无序流,
        // 流中的元素由用户定义的supplier函数生成
        Stream.generate( ()-> Math.random() ) //generate的参数是Supplier供给型接口
              .limit(5) //获取前5个元素,用于限制无限流的长度为5,如果没有limit则死循环输出
              .forEach(System.out::println); //遍历输出
    }
static <T> Stream<T> iterate​(T seed, UnaryOperator<T> f)
首先说一个两个参数的iterate,第一个参数是新流中的初始元素,
然后使用该数据做第二个参数也就是UnaryOperator函数的
入参去计算第二元素,然后把新计算得到的第二个元素作为
入参继续计算第三个元素,以此循环可以制造无限个元素,
在实际使用中一般使用limit(n)方法去获取包含n个的流。看一个例子:
Stream.iterate(0,(x)->x+2)
                .limit(3)
                .forEach(System.out::println); //输出0,2,4

在这里插入图片描述

流的中间操作:

在这里插入图片描述

中间操作分四类:筛选filter,映射map,排序sort,提取和组合
在这里插入图片描述

筛选(filter)

筛选,是按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作

该方法会接收一个返回boolean的函数作为参数,终返回一个包括所有符合条件元素的流

案例一:筛选出Integer集合中大于2的元素,并打印出来

//中间操作
    @Test
    public void test02(){
        //筛选(filter
        ArrayList<Integer> list = 
        		new ArrayList<>(Arrays.asList(1, 2, 3, 4));
        list.stream()
                .filter( x -> x >2 ) //过滤条件,当流中数据大于2的时候放入新流中
                .forEach(System.out::println); //遍历输出
//案例二:
//获取所有年龄20岁以下的学生
        ArrayList<Student> students = new ArrayList<>();
        students.add(new Student(1,19,"张三","M",true));
        students.add(new Student(1,18,"李四","M",false));
        students.add(new Student(1,21,"王五","F",true));
        students.add(new Student(1,20,"赵六","F",false));
        students.stream().filter(student -> student.getAge()<20);
    }

案例二: 筛选员工中工资高于8000的人,并形成新的集合。 形成新集合依赖collect(收集),后文有详细介绍。
实体类:

package com.fan.yygh.hosp;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private String name;  // 姓名
    private int salary; // 薪资
    private int age; // 年龄
    private String sex; //性别
    private String area;  // 地区
}

 //案例二:
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 23, "male", "New York"));
personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
personList.add(new Person("Anni", 8200, 24, "female", "New York"));
personList.add(new Person("Owen", 9500, 25, "male", "New York"));
personList.add(new Person("Alisa", 7900, 26, "female", "New York"));

List<String> listName = personList.stream()
        .filter((x) -> x.getSalary() > 8000) //条件过滤工资
        .map(Person::getName) //提取工资大于8000的人的名字
        .collect(Collectors.toList());//转成list
System.out.println(listName);

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

映射(map/flatMap)

映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为map和flatMap:

map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

映射(map/flatMap)

在对集合进行操作的时候,我们经常会从某些对象中选择性的提取某些元素的值,就像编写sql一样,指定获取表 中特定的数据列

1.指定获取特定列 SELECT name FROM student
2.在Stream API中也提供了类似的方法,map()。它接收一个函数作为方法参数,这个函数会被应用到集合中每一个 元素上,并终将其映射为一个新的元素。 案例:获取所有学生的姓名,并形成一个新的集合

//案例一:获取所有学生的姓名,并形成一个新的集合
      //中间操作map
    @Test
    public void test03(){
        //map的案例一
        ArrayList<Student> list = new ArrayList<>(Arrays.asList(
                new Student("张三",12,"man"),
                new Student("李四",32,"man"),
                new Student("王五",22,"woman"),
                new Student("赵六",45,"woman")
        ));
        list.stream()
                //.map( Student::getName) //这里使用引用
                .map( (stu)->stu.getName() )
                .forEach(System.out::println);
 //案例二:英文字符串数组的元素全部改为大写。整数数组每个元素+3。
   System.out.println("案例一:英文字符串数组的元" +
           "素全部改为大写。整数数组每个元素+3。");
   String[] arr = new String[] {"abcd", "bcdd", "defde", "fTr" };
   Arrays.stream(arr)
           .map( (s)->s.toUpperCase()/*映射规则*/)
           .forEach(System.out::println);

   int[] intArr = new int[]{1,2,3,4};
   Arrays.stream(intArr)
           .map((x) -> x+3)
           .forEach(System.out::println);

    }
    

案例三:将员工的薪资全部增加1000。

//案例三.将员工的薪资全部增加1000。
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 23, "male", "New York"));
personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
personList.add(new Person("Anni", 8200, 24, "female", "New York"));
personList.add(new Person("Owen", 9500, 25, "male", "New York"));
personList.add(new Person("Alisa", 7900, 26, "female", "New York"));
// 不改变原来员工集合的方式
List<Person> listNew = personList.stream()
       .map((person) -> {
           Person p = new Person(person.getName(), 0, 0, null, null);
           p.setSalary(person.getSalary() + 1000);//设置新工资
           return p; //返回新person
       })
       .collect(Collectors.toList());//转成集合list
System.out.println("一次改动前:" + personList);
System.out.println("一次改动后:" + listNew);

 // 改变原来员工集合的方式
 List<Person> list2 = personList.stream()
         .map((person) -> {
             person.setSalary(person.getSalary() + 1000);
             return person;
         })
         .collect(Collectors.toList());
 System.out.println(list2);

在这里插入图片描述

排序(sorted)

sorted,中间操作。有两种排序:

sorted():自然排序,流中元素需实现Comparable接口
sorted(Comparator com):Comparator排序器自定义排序

在这里插入图片描述

排序:
在这里插入图片描述
案例一:自然排序:

//自然排序:流中元素需实现Comparable接口
List<String> stringList = Arrays.asList("ccc", "aaa", "bbb", "ddd");
stringList.stream()
        .sorted()
        .forEach(System.out::println);
//输出: aaa,bbb,ccc,ddd

案例二:将员工按工资由高到低(工资一样则按年龄由大到小)排序:

//定制排序
 List<Person> personList = new ArrayList<Person>();
 personList.add(new Person("Tom", 8900, 23, "male", "New York"));
 personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
 personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
 personList.add(new Person("Anni", 8200, 24, "female", "New York"));
 personList.add(new Person("Owen", 9500, 25, "male", "New York"));
 personList.add(new Person("Alisa", 7900, 26, "female", "New York"));
 personList.stream()
         .sorted( (e1,e2)->{
             //自己实现比较规则
             if( e1.getSalary() == e2.getSalary()){//如果工资相等
                 return e1.getAge()-e2.getAge();//则按照年龄排序
             }else{//如果工资不相等,按照工资排序
                 return -(e1.getSalary()-e2.getSalary() );
             }
         })
         .forEach(System.out::println);
}

输出:
···
Person(name=Owen, salary=9500, age=25, sex=male, area=New York)
Person(name=Tom, salary=8900, age=23, sex=male, area=New York)
Person(name=Anni, salary=8200, age=24, sex=female, area=New York)
Person(name=Alisa, salary=7900, age=26, sex=female, area=New York)
Person(name=Lily, salary=7800, age=21, sex=female, area=Washington)
Person(name=Jack, salary=7000, age=25, sex=male, area=Washington)
···

提取/组合:concat,distinct,limit,skip:

合并:concat
去重:distinct
获得前几个数据:limit
跳过前几个数据再获取其他:skip

在这里插入图片描述

在这里插入图片描述

使用案例:

@Test
public void test05(){
    String[] arr1 = { "a", "b", "c", "d","c" };
    String[] arr2 = { "d", "e", "f", "g" };

    //1.合并连接:Stream.concat(stream1,stream2)
    System.out.println("合并:");
    Stream<String> stream1 = Stream.of(arr1);
    Stream<String> stream2 = Stream.of(arr2);
    Stream.concat(stream1,stream2)
            .forEach(System.out::print); //abcddefg

    //2 .去重,去除重复元素
    System.out.println("\n去重:");
    Arrays.stream(arr1)
            .distinct()
            .forEach(System.out::print);
    // 3.limit:限制从流中获得前n个数据
    System.out.println();
    Stream.iterate(0,x->x+2)
            .limit(5) //获取前5个数据
            .forEach(System.out::println);
    // 4.skip:跳过前n个数据
    Stream.generate(Math::random)
            .limit(10)//获取前10个数
            .skip(5) //并跳过前5个数
            .forEach(System.out::println);
}

其他案例:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

流的终止操作:

在这里插入图片描述

在这里插入图片描述

1.终止操作:遍历(foreach)

和集合的遍历输出一样的效果:

//1.遍历foreach
        List<Integer> list = Arrays.asList(7, 6, 9, 3, 8);
        list.stream()
                .forEach(System.out::println); //遍历输出

2.终止操作:匹配(find/match)

@Test //终止操作
    public void test06(){
        //1.遍历foreach
        List<Integer> list = Arrays.asList(7, 6, 9, 3, 8);
        list.stream()
                .forEach(System.out::println); //遍历输出
        //2.匹配(find/match)
        //findFirst:  匹配第一个
        Optional<Integer> first = list.stream()
                .findFirst(); //不能再使用其他终止操作forEach
        System.out.println("匹配第一个:"+first.get());

        //findAny:匹配任意(适用于并行流)
        Optional<Integer> any = list.parallelStream()
                .findAny();
        System.out.println("找到任意一个:"+any.get());
        //match案例3个:
        //allMatch:检查是否匹配所有元素
        boolean b1 = list.stream()
                .allMatch(x -> x > 2);
        System.out.println("检查是否所有元素大于2:"+b1);
        //anyMatch:检查是否至少匹配一个元素
        boolean b2 = list.stream()
                .anyMatch(x -> x > 2);
        System.out.println("检查是否至少有一个元素大于2:"+b2);

        //noneMatch:检查是否没有 匹配所有元素
        boolean b3 = list.stream()
                .noneMatch(x -> x > 2);
        System.out.println("检查是否没有 大于2的元素:"+b3);
    }

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3.终止操作:归约(reduce)

归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作

在这里插入图片描述

在这里插入图片描述

案例一:求Integer集合的元素之和、乘积和最大值。

@Test
public void reducetest(){
   List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
   // 求和方式1
   Optional<Integer> reduce = list.stream()
           .reduce((x, y) -> x + y);
   System.out.println("求和方式1:"+reduce.get());
   // 求和方式2
   Optional<Integer> reduce1 = list.stream()
           .reduce(Integer::sum);//调用包装类Integer的静态方法sum()
   System.out.println("求和方式2,Integer的静态方法sum:"+reduce1.get());
   // 求和方式3
   Integer reduce2 = list.stream()
           .reduce(0, Integer::sum);//参数一是用来保存归并参数的初始值,参数二是计算方法
   System.out.println("求和方式3:"+reduce2);

   // 求乘积
   Optional<Integer> reduce3 =
           list.stream().reduce((a, b) -> a * b);//参数是2个

   // 求最大值方式1
   Optional<Integer> reduce4 =
           list.stream().reduce((x, y) -> x > y ? x : y);
   // 求最大值写法2
   Optional<Integer> reduce5 = list.stream().reduce(Integer::max);
   Optional<Integer> reduce6 = list.stream().reduce(Integer::min);
   System.out.println("最大值:"+reduce5.get());
   System.out.println("最小值:"+reduce6.get());
}

案例二:求所有员工的工资之和和最高工资。

 //求所有员工的工资之和和最高工资。
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 23, "male", "New York"));
personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
personList.add(new Person("Anni", 8200, 24, "female", "New York"));
personList.add(new Person("Owen", 9500, 25, "male", "New York"));
personList.add(new Person("Alisa", 7900, 26, "female", "New York"));
// 求工资之和方式1:推荐
Optional<Integer> reduce7 = personList.stream()
        .map(Person::getSalary) //映射出所有的工资
        .reduce(Integer::sum);
System.out.println("求工资之和方式1:"+reduce7.get());
// 求工资之和方式2:
Integer sumSalary2 = personList.stream()
        .reduce(0, (sum, p) -> sum += p.getSalary(),
        (sum1, sum2) -> sum1 + sum2);
// 求工资之和方式3:
Integer sumSalary3 = personList.stream()
        .reduce(0, (sum, p) -> sum += p.getSalary(),
                Integer::sum);

// 求最高工资方式3:推荐
Integer maxSalary3 = personList.stream()
        .map(Person::getSalary).reduce(Integer::max).get();
// 求最高工资方式1:
Integer maxSalary = personList.stream()
        .reduce(0, (max, p) -> max > p.getSalary() ? max : p.getSalary(),
        Integer::max);
// 求最高工资方式2:
Integer maxSalary2 = personList.stream()
        .reduce(0, (max, p) -> max > p.getSalary() ? max : p.getSalary(),
        (max1, max2) -> max1 > max2 ? max1 : max2);

在这里插入图片描述

4.终止操作:聚合(max/min/count)

max、min、count这些字眼你一定不陌生,没错,在mysql中我们常用它们进行数据统计。Java stream中也引入了这些概念和用法,极大地方便了我们对集合、数组的数据统计工作

案例一:获取String集合中最长的元素。

public class StreamTest {
	public static void main(String[] args) {
		List<String> list =
			 Arrays.asList("adnm", "admmt", "pot", "xbangd", "weoujgsd");

		Optional<String> max = list.stream()
			.max(Comparator.comparing(String::length));
		System.out.println("最长的字符串:" + max.get());
	}
}

案例二:获取Integer集合中的最大值。

List<Integer> list = Arrays.asList(7, 6, 9, 4, 11, 6);

// 自然排序
Optional<Integer> max = list.stream().max(Integer::compareTo);
// 自定义排序(从大到小排序)
Optional<Integer> max2 = list.stream().max((o1, o2) -> o2 - o1);
System.out.println("自然排序的最大值:" + max.get());
System.out.println("自定义排序的最大值:" + max2.get());

案例三:获取员工薪资最高的人。

 //案例三:获取员工薪资最高的人。
 List<Person> personList = new ArrayList<Person>();
 personList.add(new Person("Tom", 8900, 23, "male", "New York"));
 personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
 personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
 personList.add(new Person("Anni", 8200, 24, "female", "New York"));
 personList.add(new Person("Owen", 9500, 25, "male", "New York"));
 personList.add(new Person("Alisa", 7900, 26, "female", "New York"));
 Optional<Person> max1 = personList.stream()
         .max(Comparator.comparingInt(Person::getSalary));
 System.out.println("最大工资的人:"+max1.get());

count案例:
案例四:计算Integer集合中大于6的元素的个数。

List<Integer> list = Arrays.asList(7, 6, 4, 8, 2, 11, 9);

long count = list.stream().filter(x -> x > 6).count();
System.out.println("list中大于6的元素个数:" + count);

5.终止操作:收集(collect)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

使用toMap()函数之后,返回的就是一个Map了,自然会需要key和value。
toMap()的第一个参数就是用来生成key值的,第二个参数就是用来生成value值的。
第三个参数用在key值冲突的情况下:如果新元素产生的key在Map中已经出现过了,第三个参数就会定义解决的办法。

在.collect(Collectors.toMap(Person::getId, v -> v, (a,b)->a))中:
第一个参数:Person:getId表示选择Person的getId作为map的key值;

第二个参数:v->v表示选择将原来的对象作为Map的value值

第三个参数:(a,b)->a中,如果a与b的key值相同,选择a作为那个key所对应的value值。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
并行流和顺序流:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Optionnal类:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值