JAVA8新特性Stream的常用方法 以及lamda

package com.vqseo.utils;

import org.assertj.core.util.Lists;

import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author ZhangSan_Plus
 * @version 1.0
 * @className LambdaUtils
 * @description TODO
 * @date 2020/12/28 10:15
 **/
public class LambdaUtils {
    public static void main(String[] args) {
        /**
         * Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。
         * 与迭代器不同的是Stream可以执行并行操作
         *
         * Stream:采用穿行的操作(一个item执行完成去读取另一个item)
         *
         * parallelStream:一个并行执行的流 通过默认的 ① ForkJoinPool 可提高多线程任务的速度
         * parallelStream作用: Stream具有平行处理能力,也就是将一个大任务分成多个小任务去执行 就表示每一个任务都是一个操作
         *
         * 详解Stream和parallelStream 区别 CSDN地址: https://blog.csdn.net/darrensty/article/details/79283146
         *
         * 关于什么是函数式接口:
         *      定义:只能有一个抽象方法,可以有静态方法和默认方法 可以包含Object里所有能重写的方法
         *      作用:方便直接用lambda表达式构造出实例,让代码更加整洁
         *      注解:@FunctionalInterface与@Override注解作用相似,用于在编译期间检查接口是否符合函数式接口的语法。
         * JDK中内置的几个函数式接口
         *      1.消费型接口:Consumer<T>
         *          eg:        Consumer<Goods> logConsumer = (g) -> System.out.println("买" + g.getGoodsName() + "用了" + g.getCost() + "元!");
         *      2.供给型接口:Supplier<T>
         *          eg:Supplier<String>suo=()->"针不戳";
         *      3.函数式接口:Function<T,R>
         *      4.断言型接口:Predicate<T>
         *          eg:Predicate<String> p1=(t)->t.equals("nice");
         *
         *
         *
         *
         * 注:① ForkJoinPool(将一个大任务拆分成多个小任务后,使用fork可以将小任务分发给其他线程同时处理,使用join可以将多个线程处理的结果进行汇总;这实际上就是分治思想的并行版本。)
         *      实现思路:if(任务小){直接计算}else{拆分成多个子任务执行}
         *      如果是普通的ThreadPoolExecutor(线程池)就会出现线程池中只有一个线程正在处理这个大任务而其他线程却空闲着,这会导致CPU负载不均衡,空闲的处理器无法帮助工作。
         */
        List<String> list = Lists.newArrayList();
        //串行流(一个接着一个执行)
        Stream<String> stream = list.stream();
        //并行流(类似线程并发的一种 统称为并行流) 执行效率快
        Stream<String> stringStream = list.parallelStream();

        /**1.流常用的创建方法 **/

        //1.1 将数组采用Arrays 转成流
        Integer[] nums = new Integer[10];
        Stream<Integer> numStream = Arrays.stream(nums);

        //1.2 Stream中的静态方法:of()、iterate()、generate()

        //--数组
        Stream<Integer> of = Stream.of(1, 2, 3, 4, 5, 6);

        //--每个x+2 获取6个
        Stream<Integer> iterate = Stream.iterate(0, (x) -> x + 2).limit(6);

        //--生成两个double类型的随机数
        Stream<Double> generate = Stream.generate(Math::random).limit(2);

        //1.3 Pattern.splitAsStream() 方法,将字符串分隔成流  采用正则方式生成Stream
        Pattern pattern = Pattern.compile(",");
        Stream<String> splitAsStream = pattern.splitAsStream("a,b,c,d");
        /**
         * 2.流的中间操作
         *      2.1 筛选和切片
         *          filter:过滤流中的某些元素
         *          limit(n):获取n个元素
         *          skip(n):跳过n元素,配合limit(n)可实现分页
         *          distinct:通过流中元素的 hashCode() 和 equals() 去除重复元素
         *      2.2 映射
         *           map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
         *           flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
         *      2.3 排序
         *           sorted():自然排序,流中元素需实现Comparable接口
         *           sorted(Comparator com):定制排序,自定义Comparator排序器
         *      2.4 消费
         *           peek:如同于map,能得到流中的每一个元素。但map接收的是一个Function表达式,有返回值;而peek接收的是Consumer表达式,没有返回值。
         */

        Stream<Integer> streamOf = Stream.of(6, 4, 6, 7, 3, 9, 8, 10, 12, 14, 14);
        //6 6 7 9 8 10 12 14 14
        streamOf.filter(s -> s > 5)
                //6 7 9 8 10 12 14
                .distinct()
                //9 8 10 12 14
                .skip(2)
                //9 8
                .limit(2);


        //将每个元素转成一个新的且不带逗号的元素(争对每个元素)
        List<String> mapList = Arrays.asList("a,b,c", "1,2,3");
        Stream<String> s1 = mapList.stream().map(s -> s.replaceAll(",", ""));

        //将每一个元素转化成 一个流
        Stream<String> flatMap = mapList.stream().flatMap(s -> {
            //将每个元素转换成一个stream
            String[] split = s.split(",");
            Stream<String> s2 = Arrays.stream(split);
            return s2;
        });

        //String自身实现了Comparable接口
        /**
         * public final class String implements java.io.Serializable, Comparable<String>, CharSequence{}
         */
        List<String> sortList = Arrays.asList("aa", "ff", "dd");
        list.stream().sorted();

        //自定义排序:先按姓名升序,姓名相同则按年龄升序
        List<Student> studentList = Lists.newArrayList();
        studentList.add(new Student("张三", 10));
        studentList.add(new Student("李四", 20));
        studentList.add(new Student("李四", 42));
        studentList.add(new Student("王五", 30));
        studentList.stream().filter(c -> c.getName().startsWith("王") && c.getAge() == 30).collect(Collectors.toList());
        studentList.sort(Comparator.comparing(Student::getAge));


        studentList.stream().sorted((o1, o2) -> {
            if (o1.getName().equals(o2.getName())) {
                return o1.getAge() - o2.getAge();
            } else {
                return o1.getName().compareTo(o2.getName());
            }
        });
        //排序
        studentList.sort(Comparator.comparing(Student::getName).thenComparing(Student::getAge));

        List<Student> peekList = Lists.newArrayList();


        peekList.add(new Student("aa", 10));
        peekList.add(new Student("bb", 20));
        peekList.stream().peek(c -> c.setAge(100));

        /**
         * 3.流的终止操作
         *      3.1 匹配和聚合操作
         *              allMatch:接收一个 Predicate 函数,当流中每个元素都符合该断言时才返回true,否则返回false
         *              noneMatch:接收一个 Predicate 函数,当流中每个元素都不符合该断言时才返回true,否则返回false
         *              anyMatch:接收一个 Predicate 函数,只要流中有一个元素满足该断言则返回true,否则返回false
         *              findFirst:返回流中第一个元素
         *              findAny:返回流中的任意元素
         *              count:返回流中元素的总个数
         *              max:返回流中元素最大值
         *              min:返回流中元素最小值
         *      3.2 违约操作
         *              Optional<T> reduce(BinaryOperator<T> accumulator):
         *                  第一次执行时,accumulator函数的第一个参数为流中的第一个元素,第二个参数为流中元素的第二个元素;第二次执行时,第一个参数为第一次函数执行的结果,第二个参数为流中的第三个元素;依次类推。
         *              T reduce(T identity, BinaryOperator<T> accumulator):
         *                  流程跟上面一样,只是第一次执行时,accumulator函数的第一个参数为identity,而第二个参数为流中的第一个元素。
         *              <U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> combiner):
         *                  在串行流(stream)中,该方法跟第二个方法一样,即第三个参数combiner不会起作用。在并行流(parallelStream)中,我们知道流被fork join出多个线程进行执行,此时每个线程的执行流程就跟第二个方法reduce(identity,accumulator)一样,而第三个参数combiner函数,则是将每个线程的执行结果当成一个新的流,然后使用第一个方法reduce(accumulator)流程进行规约。
         *      3.3 收集操作
         *              collect:接收一个Collector实例,将流中元素收集成另外一个数据结构。
         *              Collector<T, A, R> 是一个接口,有以下5个抽象方法:
         *                      Supplier<A> supplier():创建一个结果容器A
         *                      BiConsumer<A, T> accumulator():消费型接口,第一个参数为容器A,第二个参数为流中元素T。
         *                      BinaryOperator<A> combiner():函数接口,该参数的作用跟上一个方法(reduce)中的combiner参数一样,将并行流中各                                                                 个子进程的运行结果(accumulator函数操作后的容器A)进行合并。
         *                      Function<A, R> finisher():函数式接口,参数为:容器A,返回类型为:collect方法最终想要的结果R。
         *                      Set<Characteristics> characteristics():返回一个不可变的Set集合,用来表明该Collector的特征。有以下三个特征:
         *                              CONCURRENT:表示此收集器支持并发。(官方文档还有其他描述,暂时没去探索,故不作过多翻译)
         *                              UNORDERED:表示该收集操作不会保留流中元素原有的顺序。
         *                              IDENTITY_FINISH:表示finisher参数只是标识而已,可忽略。
         */
        List<Integer> endList = Arrays.asList(1, 2, 3, 4, 5);
//        //必须是每一个元素都满足该条件
        System.out.println(endList.stream().allMatch(c -> c > 10));
        //都不符合该条件
        System.out.println(endList.stream().noneMatch(c -> c > 10));
        //有一个满足
        System.out.println(endList.stream().anyMatch(c -> c > 4));
        //返回流中的第一个元素
        System.out.println(endList.stream().findFirst().get());
        //返回流中的任意元素
        System.out.println(endList.stream().findAny().get());
        //返回流中元素的总个数
        System.out.println(endList.stream().count());
        //返回流中的最大元素
        System.out.println(endList.stream().max(Integer::compareTo).get());
        //返回流中的最小元素
        System.out.println(endList.stream().min(Integer::compareTo).get());

        //经过测试,当元素个数小于24时,并行时线程数等于元素个数,当大于等于24时,并行时线程数为16
//        System.out.println(optList.stream().mapToInt((s) -> s).sum());
        List<Integer> optList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24);
        //BinaryOperator 表达式格式 (x,y)->x+y  Optional<T> reduce(BinaryOperator<T> accumulator)
        System.out.println(optList.stream().reduce((x1, x2) -> x1 + x2).get());
        //T reduce(T identity, BinaryOperator<T> accumulator)
        System.out.println(optList.stream().reduce(10, (x1, y1) -> x1 + y1));
        //<U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> combiner)
        //identity 参数 BiFunction 方法体 BinaryOperator 表达式
        Integer reduce = optList.stream().reduce(0, (x1, x2) -> {
//            System.out.println("stream accumulator: x1:" + x1 + "  x2:" + x2);
            return x1 - x2;
        }, (x1, x2) -> {
//            System.out.println("stream combiner: x1:" + x1 + "  x2:" + x2);
            return x1 * x2;
        });
//        System.out.println(reduce);
        Integer reduce1 = optList.parallelStream().reduce(0, (x1, x2) -> {
            System.out.println("parallelStream accumulator: x1:" + x1 + "  x2:" + x2);
            return x1 - x2;
        }, (x1, x2) -> {
            System.out.println("parallelStream combiner: x1:" + x1 + "  x2:" + x2);
            return x1 * x2;
        });
        System.out.println(reduce1);

        //Collector 工具库:Collectors
        Student student = new Student();
        List<Student> students = Lists.newArrayList();
        students.add(new Student("aa", 10));
        students.add(new Student("bb", 20));
        students.add(new Student("cc", 30));
        //获取年龄属性并转成List
        List<Integer> collect = students.stream().map(Student::getAge).collect(Collectors.toList());
        //获取年龄属性并转成Set
        Set<Integer> collect1 = students.stream().map(Student::getAge).collect(Collectors.toSet());
        //获取当前学生并转成map
        Map<String, Integer> studentMap = students.stream().collect(Collectors.toMap(Student::getName, Student::getAge));
        //字符串分隔连接
        String collect2 = students.stream().map(Student::getName).collect(Collectors.joining(","));
        //获取学生总数
        Long count = students.stream().collect(Collectors.counting());
        //获取学生的最大年龄
        Integer maxAge = students.stream().map(Student::getAge).collect(Collectors.maxBy(Integer::compareTo)).get();
        //获取学生的最小年龄
        Integer minAge = students.stream().map(Student::getAge).collect(Collectors.minBy(Integer::compareTo)).get();
        //所有人的年龄
        Integer sumAge = students.stream().collect(Collectors.summingInt(Student::getAge));
        //所有人的平均年龄
        Double avgAge = students.stream().collect(Collectors.averagingInt(Student::getAge));
        //分组
        Map<Integer, List<Student>> ageMap = students.stream().collect(Collectors.groupingBy(Student::getAge));
        ageMap.forEach((k, v) -> {
            System.out.println("key" + k + "Value" + v);
        });
        Map<Boolean, List<Student>> partMap = students.stream().collect(Collectors.partitioningBy(v -> v.getAge() > 10));
        Integer allAge = students.stream().map(Student::getAge).collect(Collectors.reducing(Integer::sum)).get();

    }
}

猜你喜欢

转载自blog.csdn.net/qq_43565087/article/details/111870172