• Java——Stream流的学习


    在开发过程中,经常或忽略流的使用,导致用的不熟练,于是抽时间系统的学习下stream的使用,找了哔哩哔哩的教程跟着看看练练。

    准备工作

    创建Book、Aurhor实体类,初始化数据

    public static List<Author> getAuthors() {
            Author author1 = new Author(1L, "蒙多", 33, "一个从菜刀中明悟哲理的祖安人", null);
            Author author2 = new Author(2L, "亚拉索", 15, "狂风也追逐不上他的思考速度", null);
            Author author3 = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);
            Author author4 = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);
    
            List<Book> books1 = new ArrayList<>();
            List<Book> books2 = new ArrayList<>();
            List<Book> books3 = new ArrayList<>();
    
            books1.add(new Book(1L, "刀的两侧是光明与黑暗", "哲学,爱情", 88, "用一把刀划分了爱情"));
            books1.add(new Book(2L, "一个人不能死在同一把刀下", "个人成长,爱情", 99, "讲述如何成功"));
    
            books2.add(new Book(3L, "那风吹不到的地方", "哲学", 85, "带你用思维去领略世界的尽头"));
            books2.add(new Book(3L, "那风吹不到的地方", "哲学", 85, "带你用思维去领略世界的尽头"));
            books2.add(new Book(4L, "吹或不吹", "爱情,个人传记", 65, "一个哲学家的恋爱观注定很难"));
    
            books3.add(new Book(5L, "你的剑就是我的剑", "爱情", 56, "无法想象一个武者"));
            books3.add(new Book(5L, "风与剑", "个人传记", 100, "两个哲学家灵魂与肉体的碰撞"));
            books3.add(new Book(5L, "风与剑", "个人传记", 100, "两个哲学家灵魂与肉体的碰撞"));
    
            author1.setBooks(books1);
            author2.setBooks(books2);
            author3.setBooks(books3);
            author4.setBooks(books3);
    
            List<Author> authors = new ArrayList<>(Arrays.asList(author1, author2, author3, author4));
            return authors;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    创建流

    // 1.单列集合
    private static void test01(List<Author> authors) {
    	authors.stream().distinct().filter(author -> author.getAge()<18).forEach(author -> System.out.println(author.getName()));
    }
    
    • 1
    • 2
    • 3
    • 4
    // 2.数组流
    private static void test02() {
        Integer[] arr = {1,2,3,4,5};
    //  IntStream stream = Arrays.stream(arr);
        Stream<Integer> stream = Stream.of(arr);
        stream.distinct().filter(value -> value > 2).forEach(value -> System.out.println(value));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    // 3.双列集合   map流
    private static void test03() {
        Map<String, Integer> map = new HashMap<>();
        map.put("张三", 18);
        map.put("李四", 33);
        map.put("王五", 25);
    
        Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();
        stream.filter(entry -> entry.getValue()>20).forEach(entry -> System.out.println(entry.getKey()));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    中间操作

    • filter 对流中的操作进行过滤,符合条件的返回
      使用的函数式接口是:Predicate,参数是一个实体,拥有抽象方法:boolean test(T t);
    authors.stream().filter(new Predicate<Author>() {
        @Override
        // 匿名内部类的test方法,将传入的author进行判断,返回符合条件的
        public boolean test(Author author) {
            return author.getName().length() > 1;
        }
    }).forEach(author -> System.out.println(author.getName()));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    该操作将作者名字长度>1 的作者名列出来

    • map 把流中元素进行计算或转换
      使用的函数式接口是:Function,参数是一个实体,和一个要将实体转化的结果result,拥有抽象方法:R apply(T t);
      (1)进行转换,该操作将作者名字列出来
    private static void test05(List<Author> authors) {
        authors.stream().map(new Function<Author, String>() {
            @Override
            // 匿名内部类的apply方法,将传入的author进行需要的结果返回
            public String apply(Author author) {
                return author.getName();
            }
       }).forEach(s -> System.out.println(s));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    (2)进行计算,该操作将作者年龄分别+10

    authors.stream().map(author -> author.getAge())
                    .map(new Function<Integer, Integer>() {
                        @Override
                        public Integer apply(Integer age) {
                            return age + 10;
                        }
                    })
                    .forEach(s -> System.out.println(s));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    第一个map是获取作者的年龄,然后第二个map则将年龄转换为年龄,只是经过了+10计算,我们打断点看看
    在这里插入图片描述
    流经过第一个map后转换为了Integer
    在这里插入图片描述
    经过第二个map后将第一个Integer进行+10计算,类型不变

    • distinct 将元素进行去重操作
      注意:distinct 依赖Object 的equals方法来判断对象是否相同,对象要重写equals方法。
    authors.stream().distinct().forEach(author -> { System.out.println(author.getName()); });
    
    • 1

    该操作直接通过distinct去重
    当然也可以使用前面的map提取出名字,再去重,比上面的麻烦些

    authors.stream().distinct().map(new Function<Author, String>() {
                @Override
                public String apply(Author author) {
                    return author.getName();
                }
            }).forEach(name -> { System.out.println(name); });
    
    // 一样
    authors.stream().distinct().map(author -> author.getName()).forEach(name -> { System.out.println(name); });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    该操作先使用map将Author对象转换为姓名的String,然后在去重

    • flatMap
      上面的Map是把一个对象转换成另一个对象作为流中的元素,而flatMap是把一个对象转换为多个对象作为流中的元素

    使用的函数式接口是:new Function,将一个对象转换成Stream对象

    (1)打印所有书籍的名字,要求对重复的元素进行去重。

    authors.stream()
    	   .flatMap(new Function<Author, Stream<Book>>() {
    	        // 这里可以通过idea进行lambda转换,为了清晰就不转了
                @Override
                public Stream<Book> apply(Author author) {
                    return author.getBooks().stream();
                }
               })
            .distinct()
            .forEach(name -> { System.out.println(name); });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    如果使用Map,将作者对象提取出书籍对象,还需要再对书籍对象List进行遍历去重,比较麻烦。
    首先使用flatMap将每个作者对象中的书籍对象流提取出来,然后直接在书籍对象流中进行去重,输出书籍名称。
    在这里插入图片描述
    在这里插入图片描述
    (2)打印现有数据的所有分类,要求对分类进行去重,不能出现这种格式:哲学,爱情,需要转成两个分类

    authors.stream()
                    .flatMap(author -> author.getBooks().stream())
                    .distinct()
                    // 将分类进行分割成数组后,转成流进行去重
                    .flatMap(book -> Arrays.stream(book.getCategory().split(",")))
                    .distinct()
                    .forEach(category -> System.out.println(category));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述
    第一次使用flatmap将作者对象转换成多个书籍对象流
    在这里插入图片描述

    第二次使用flatmap将书籍对象的分类转换成多个分类流

    终结操作

    • forEach 对流中元素进行遍历操作
    • count 获取当前流中元素的个数
      (1)打印这些作家所出书籍的数目,注意删除重复元素
      因为count属于终结操作,会有返回值
    long count = authors.stream()
                    .flatMap(author -> author.getBooks().stream())
                    .distinct()
                    .count();
    System.out.println("书籍count = " + count);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述
    使用flatMap获取每个书籍对象,去重计算
    在这里插入图片描述

    • min和max 求流中的最值
      (1)获取这些作家的所出书籍的最高分和最低分
    Optional<Integer> max = authors.stream()
                    .flatMap(author -> author.getBooks().stream())
                    .map(book -> book.getScore())
                    .max(new Comparator<Integer>() {
                        @Override
                        public int compare(Integer score1, Integer score2) {
                            return score1 - score2;
                        }
                    });
    System.out.println("书籍评分max = " + max.get());
    
    Optional<Integer> min = authors.stream()
                    .flatMap(author -> author.getBooks().stream())
                    .map(book -> book.getScore())
                    .min(new Comparator<Integer>() {
                        @Override
                        public int compare(Integer score1, Integer score2) {
                            return score1 - score2;
                        }
                    });
    System.out.println("书籍评分min = " + min .get());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    先使用flatMap将作者对象转换成多个书籍对象流,然后用map获取书籍对象中的评分对象,进行max和min计算

    • collect 把当前流转换成一个集合
      (1)获取一个存放所有作者名字的List集合
    List<String> list = authors.stream()
                    .map(author -> author.getName())
                    .distinct()
                    .collect(Collectors.toList());
    
    System.out.println("list = " + list);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (2)获取一个所有书名的set集合

    Set<String> set = authors.stream()
                    .flatMap(author -> author.getBooks().stream())
                    .map(book -> book.getName())
                    .collect(Collectors.toSet());
    
    System.out.println("set = " + set);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (3)获取一个map集合,key为作者名,value为List

    Map<String, List<Book>> map = authors.stream()
                    // 去重避免key重复
                    .distinct()
                    .collect(Collectors.toMap(new Function<Author, String>() {
                        @Override 
                        // 这里的匿名内部类将传入作者对象,获取作者名作为key
                        public String apply(Author author) { 
                            return author.getName(); 
                        }
                        }, new Function<Author, List<Book>>() {
                        @Override 
                        // 这里的匿名内部类将传入作者对象,获取书籍list作为value
                        public List<Book> apply(Author author) { 
                            return author.getBooks(); 
                        }
                    }));
    
    System.out.println("map = " + map);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    简化lambda表达式

    Map<String, List<Book>> map = authors.stream()
                    // 去重避免key重复
                    .distinct()
                    .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
    
    System.out.println("map = " + map);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • anyMatch 判断流中是否有任意符合匹配条件的元素,符合返回true
    boolean b = authors.stream().anyMatch(author -> author.getAge() > 29);
    
    System.out.println("b = " + b);
    
    • 1
    • 2
    • 3

    判断是否有年龄在29以上的作家

    • allMatch 判断流中元素是否都符合条件,都符合为true,否则为false
    boolean b = authors.stream().allMatch(author -> author.getAge() >= 18);
    System.out.println("b = " + b);
    
    • 1
    • 2

    判断是否所有作家都是成年人

    • noneMatch 判断流中元素是否都不符合条件,是为true,否为false
    boolean b = authors.stream().noneMatch(author -> author.getAge() > 100);
    System.out.println("b = " + b);
    
    • 1
    • 2

    判断作家是否都没有超过100岁的

    • findAny 获取流中符合条件的任意一个元素,不保证为流中的第一个元素
    Optional<Author> au = authors.stream().filter(author -> author.getAge() > 18).findAny();
    
    System.out.println("名字:" + au.get().getName());
    
    • 1
    • 2
    • 3

    这里用的get方法获取数据,但是可能出现找不到符合条件的数据,这时候get就会报错,如:
    在这里插入图片描述
    所以改成:

    Optional<Author> au = authors.stream().filter(author -> author.getAge() > 98).findAny();
    
    au.ifPresent(author -> System.out.println(author.getName()));
    
    • 1
    • 2
    • 3

    获取任意一个大于18的作家,输出名字

    • findFirst 获取流中的第一个元素
    Optional<Author> author = authors.stream()
                    .sorted((o1, o2) -> o1.getAge() - o2.getAge())
                    .findFirst();
    
    author.ifPresent(author1 -> System.out.println(author1.getName()));
    
    • 1
    • 2
    • 3
    • 4
    • 5

    获取年龄最小的作家,输出名字

    • reduce归并 对流中的数据按照指定的计算方式计算出一个结果(缩减操作)
      把stream中的元素组合起来,传入初始化值,按照指定的计算方式和元素进行计算,计算结果再和下一个元素进行计算,依次计算完

    reduce有三种重载方式

    1. 2个参数的
      T reduce(T identity, BinaryOperator accumulator);
    T result = identity;
    for (T element : this stream) {
    	result = accumulator.apply(result, element)
    }
    return result;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    传入初始化值作为第一个参数identity,传入计算方法accumulator.apply 进行初始化值和元素的计算

    例子:
    (1)使用reduce对作者年龄进行求和

    Integer result = authors.stream()
                    .distinct()
                    .map(author -> author.getAge())
                    // 传入初识值和计算方法
                    .reduce(0, new BinaryOperator<Integer>() {
                        @Override
                        public Integer apply(Integer result, Integer element) {
                            return result + element;
                        }
                    });
    
    System.out.println("result = " + result);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    lambda写

    Integer result = authors.stream()
                    .distinct()
                    .map(author -> author.getAge())
                    // 传入初识值和计算方法
                    .reduce(0, (result1, element) -> result1 + element);
    
    System.out.println("result = " + result);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    (2)使用reduce求所有作者年龄最大值

    Integer max = authors.stream()
                    .distinct()
                    .map(author -> author.getAge())
                    .reduce(Integer.MIN_VALUE, new BinaryOperator<Integer>() {
                        @Override
                        public Integer apply(Integer result, Integer element) {
                            return result > element ? result : element;
                        }
                    });
    System.out.println("max = " + max);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    (3)使用reduce求所有作者年龄最小值

    Integer min = authors.stream()
                    .distinct()
                    .map(author -> author.getAge())
                    .reduce(Integer.MAX_VALUE, new BinaryOperator<Integer>() {
                        @Override
                        public Integer apply(Integer result, Integer element) {
                            return result > element ? element : result;
                        }
                    });
    
    System.out.println("min = " + min);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1. 1个参数的
      Optional reduce(BinaryOperator accumulator);
    boolean foundAny = false;
    T result = null;
    for (T element : this stream) {
    	if (!foundAny) {
    		foundAny = true;
    		result = element;
    	} else {
    		result = accumulator.apply(result, element);
    	}
    }
    
    return foundAny ? Optional.of(result) : Optional.empty();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    该方法只传入了一个计算方式,根据实现方法,可以看到将流中的第一个元素作为了第一个元素result,然后后续进行else内部的计算

    例如:

    Optional<Integer> optional = authors.stream()
                    .distinct()
                    .map(author -> author.getAge())
                    // 直接传入计算方法
                    .reduce((result, element) -> result > element ? element : result);
    
    optional.ifPresent(integer -> System.out.println(integer));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 相关阅读:
    Android 获取SIM卡号码权限申请
    dompdf,这么做就可以支持中文了
    B. Bin Packing Problem(线段树+multiset)
    MAVEN中三种packaging方式
    MySQL导入导出视图
    双端队列--二叉树 Z 字层序遍历
    logback--进阶--03--日志打印步骤
    Python15题day11
    Python UI自动化 —— pytest常用运行参数解析、pytest执行顺序解析
    Centos7安装配置中文输入法
  • 原文地址:https://blog.csdn.net/qq_32015565/article/details/135964670