Java8新特性强化(二)

目录

3、Stream流

3.1、概述

3.2、案例数据准备

3.4、常用操作

3.4.1、创建流

3.4.2、中间操作

filter

map

distinct

sorted

limit

skip

flatMap

3.4.3、终结操作

foreach

count

max&min

collect

匹配相关

anyMatch

allMatch

noneMatch

查找相关

findAny

findFirst

reduce归并(难点)

3.5、Stream使用的注意事项


3、Stream流

3.1、概述

        Java8的Stream使用的是函数式编程模式,如同它的名字一样,它可以被用来对集合或数组进行链状流式的操作,可以更方便我们对集合或数组操作。

        之前的inputStream、outputStream都是io流,是数据读写使用的,此处的Stream都是对数组集合操作用的

3.2、案例数据准备

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
 * @Description 入门案例
 * @Author:SQJ
 * @DATE: 2022/10/11
 */
public class stream1 {

    public static void main(String[] args) {

        //需求:我们可以调用getAuthors方法获取到作家的集合,现在需要打印所有年龄小于18的作家的名字,并且注意去重。
        getAuthors().stream()   //转换为Stream流
                .distinct()     //去重
                .filter(new Predicate<Author>() {   //过滤  条件为年龄小于18
                    @Override
                    public boolean test(Author author) {
                        return author.getAge()<18;
                    }
                }).forEach(new Consumer<Author>() {     //过滤的结果进行处理
            @Override
            public void accept(Author author) {
                System.out.println(author.getName());
            }
        });

        System.out.println("-------------");

        //对上述的方法通过lambda表达式转换
        getAuthors().stream()
                .distinct()     
                .filter(author -> author.getAge()<18)
                .forEach((Author author) -> System.out.println(author.getName()));
    }



    // 初始化一些数据
    private static List<Author> getAuthors() {
        Author author1 = new Author(1L, "sqj", "my introduction 1", 18, null);
        Author author2 = new Author(2L, "www", "my introduction 2", 19, null);
        Author author3 = new Author(3L, "hhh", "my introduction 3", 14, null);
        Author author4 = new Author(4L, "ddd", "my introduction 4", 29, null);
        Author author5 = new Author(5L, "eee", "my introduction 5", 12, null);

        List<Book> books1 = new ArrayList<>();
        List<Book> books2 = new ArrayList<>();
        List<Book> books3 = new ArrayList<>();

        // 上面是作者和书
        books1.add(new Book(1L, "类别,分类啊", "书名1", 45D, "这是简介哦"));
        books1.add(new Book(2L, "高效", "书名2", 84D, "这是简介哦"));
        books1.add(new Book(3L, "喜剧", "书名3", 83D, "这是简介哦"));

        books2.add(new Book(5L, "天啊", "书名4", 65D, "这是简介哦"));
        books2.add(new Book(6L, "高效", "书名5", 89D, "这是简介哦"));

        books3.add(new Book(7L, "久啊", "书名6", 45D, "这是简介哦"));
        books3.add(new Book(8L, "高效", "书名7", 44D, "这是简介哦"));
        books3.add(new Book(9L, "喜剧", "书名8", 81D, "这是简介哦"));

        author1.setBookList(books1);
        author2.setBookList(books2);
        author3.setBookList(books3);
        author4.setBookList(books3);
        author5.setBookList(books2);

        return new ArrayList<>(Arrays.asList(author1, author2, author3, author4, author5));
    }

}

需求:我们可以调用getAuthors方法获取到作家的集合,现在需要打印所有年龄小于18的作家的名字,并且注意去重。

实现:

    private static void test00() {
        //需求:我们可以调用getAuthors方法获取到作家的集合,现在需要打印所有年龄小于18的作家的名字,并且注意去重。
        getAuthors().stream()   //转换为Stream流
                .distinct()     //去重
                .filter(new Predicate<Author>() {   //过滤  条件为年龄小于18
                    @Override
                    public boolean test(Author author) {
                        return author.getAge()<18;
                    }
                }).forEach(new Consumer<Author>() {     //过滤的结果进行处理
            @Override
            public void accept(Author author) {
                System.out.println(author.getName());
            }
        });

        System.out.println("-------------");

        //对上述的方法通过lambda表达式转换
        getAuthors().stream()
                .distinct()     //去重
                .filter(author -> author.getAge()<18)
                .forEach((Author author) -> System.out.println(author.getName()));
    }

3.4、常用操作

3.4.1、创建流

单列集合:集合对象.stream();

数组:Arrays.stream(数组)或者使用Stream.of来创建

        Integer [] arr = {1,2,3,4,5};
        Stream<Integer> stream = Arrays.stream(arr);
        Stream<Integer> stream2 = Stream.of(arr);

        stream.filter(integer -> integer>3)
                .forEach(integer -> System.out.println(integer));

双列集合:转换成单列集合后再创建

map不能直接转换为Stream流,可以使用map的entryset方法转换为单列集合set

//双列集合  map    转换为单列集合再创建
        HashMap<String, Integer> hashMap = new HashMap<>();
        hashMap.put("sqj",15);
        hashMap.put("www",16);
        hashMap.put("sss",17);
        hashMap.put("sss",17);
        //Stream<Map.Entry<String, Integer>> stream1 = hashMap.entrySet().stream();
        Set<Map.Entry<String, Integer>> entrySet = hashMap.entrySet();  //将map转换为一个set,其中set的每一个元素就是map的一对键值对
        entrySet.stream()
                .filter(new Predicate<Map.Entry<String, Integer>>() {
                    @Override
                    public boolean test(Map.Entry<String, Integer> stringIntegerEntry) {
                        return stringIntegerEntry.getValue()>15;
                    }
                }).distinct()
                .sorted(new Comparator<Map.Entry<String, Integer>>() {
                    @Override
                    public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                        return o1.getValue()-o2.getValue();
                    }
                })
                .forEach(new Consumer<Map.Entry<String, Integer>>() {
                    @Override
                    public void accept(Map.Entry<String, Integer> stringIntegerEntry) {
                        System.out.println(stringIntegerEntry.getKey());
                    }
                });

        entrySet.stream()
                .filter((Map.Entry<String, Integer> stringIntegerEntry) ->stringIntegerEntry.getValue()>15).distinct()
                .sorted((Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2)-> o2.getValue()-o1.getValue())
                .forEach(stringIntegerEntry -> System.out.println(stringIntegerEntry.getKey()));

3.4.2、中间操作

filter

对流中的元素进行条件过滤,符合过滤条件的才会继续留在流中

    private static void test00() {
        //需求:我们可以调用getAuthors方法获取到作家的集合,现在需要打印所有年龄小于18的作家的名字,并且注意去重。
        getAuthors().stream()   //转换为Stream流
                .distinct()     //去重
                .filter(new Predicate<Author>() {   //过滤  条件为年龄小于18
                    @Override
                    public boolean test(Author author) {
                        return author.getAge()<18;
                    }
                }).forEach(new Consumer<Author>() {     //过滤的结果进行处理
            @Override
            public void accept(Author author) {
                System.out.println(author.getName());
            }
        });

map

对流中的元素进行计算或者数据类型进行转换

需求:打印所有作家的姓名

实现:

 private static void test03() {
        List<Author> authors = getAuthors();
        //转换
        authors.stream()
                .map(author -> author.getName())
                .forEach(a -> System.out.println(a));

        System.out.println("----------");
        //计算
        authors.stream()
                .map(author -> author.getAge())
                .map(age -> age -10)
                .forEach(a -> System.out.println(a));
    }

distinct

去重操作,需要在bean对象重写equals方法,即加注解 @EqualsAndHashCode

注意:distinct方法是依赖Object的equals方法来判断是否是相同对象的。所以需要注意重写equals方法

sorted

sorted两个方法。无参方法使用的时候需要实现Conparable接口,实现接口下的方法

有参方法使用的时候直接创建Comparable接口

    //对流中的元素按照年龄降序排序,并要求不能有重复的元素
    private static void test5() {
        getAuthors().stream()
                .distinct()
                .sorted((o1, o2) -> o2.getAge()-o1.getAge())
                .forEach(a -> System.out.println(a));

    }

limit

可以设置流的最大长度,超出的部分将被抛弃掉

例如:对流中元素按照年龄进行降序排序,并且要求不能有重复的元素,然后打印其中年龄最大的两个作家的姓名

//要求对流中的元素进行排序,并且要求不能有重复的元素,然后打印其中年龄最大的两个作家的姓名
    private static void test8() {
        getAuthors().stream()
                .distinct()
                .sorted((o1,o2)->o2.getAge()-o1.getAge())
                .limit(2)
                .forEach(a-> System.out.println(a));

    }

skip

跳过流中的前n个元素,返回剩下的元素

例如:打印除了年龄最大的作家以外的其他作家,要求不能有重复元素,并且按照年龄降序排列。

//打印除了年龄最大的作家以外的其他作家,要求不能有重复元素,并且按照年龄降序排列。
    private static void test9() {
        getAuthors().stream()
                .distinct()
                .sorted((o1,o2)-> o2.getAge()-o1.getAge())
                .skip(1)
                .forEach(author -> System.out.println(author));
    }

flatMap

map只能把一个对象转换成另一个对象来作为流中的元素,而flatMap可以把一个对象转换成多个对象作为流中的元素

    //打印所有书籍的名字,要求对重复的元素进行去重
    private static void test10() {
        getAuthors().stream()
            .flatMap(author-> author.getBookList().stream())
                .distinct()
                .forEach( a-> System.out.println(a.getName()));


    //打印现有数据的所有分类,要求对分类进行去重,不能出现这种格式:哲学,爱情
    private static void test11() {
        getAuthors().stream()
                .flatMap(author -> author.getBookList().stream())
                .distinct()
                .flatMap(book -> Arrays.stream(book.getCategory().split(",")))
                .distinct()
                .forEach(a -> System.out.println(a));

    }

3.4.3、终结操作

如果流的一系列的操作要成功触发并生效,那必须需要有终结操作,一个流只能做一次终结操作。

foreach

对流中的元素进行遍历操作,我们通过传入的参数去指定对遍历到的元素进行什么具体的操作

count

可以用来获取当前流中的元素

例子:打印这些作家的所处书籍的数目,注意删除重复元素

    //打印这些作家的所出书籍的数目,注意删除重复元素
    private static void test12() {
        long count = getAuthors().stream()
                .distinct()
                .flatMap(author -> author.getBookList().stream())
                .distinct()
                .count();
        System.out.println(count);
    }

max&min

可以用来获取流中的最值

例子:分别获取这些作家的所出书籍的最高分和最低分并打印。

    //分别获取这些作家的所出书籍的最高分和最低分并打印。
    private static void test13() {
        Double aDouble = getAuthors().stream()
                .flatMap(author -> author.getBookList().stream())
                .distinct()
                .map(book -> book.getScore())
                .min(new Comparator<Double>() {
                    @Override
                    public int compare(Double o1, Double o2) {
                        return o1.intValue() - o2.intValue();
                    }
                }).get();
        System.out.println(aDouble);
        
    }

collect

把当前流转换成一个集合

例子:获取一个存放所有作者名字的 List 集合(tolist方法)

    //例子:获取一个存放所有作者名字的 List 集合
    private static void test14() {
        List<String> collect = getAuthors().stream()
                .map(author -> author.getName())
                .collect(Collectors.toList());
        System.out.println("collect list = " + collect);
    }

例子:获取一个所有书名的 Set 集合(toset)

    //例子:获取一个所有书名的 Set 集合
    private static void test15() {
        Set<String> collect = getAuthors().stream()
                .flatMap(author -> author.getBookList().stream())
                .distinct()
                .map(book -> book.getName())
                .collect(Collectors.toSet());
        System.out.println("collect set = " + collect);
    }

例子:获取一个 Map 集合,map 的 key 为作者名,value 为 List<Book>(tomap方法)

    //例子:获取一个 Map 集合,map 的 key 为作者名,value 为 List<Book>
    private static void test16() {
        Map<String, List<Book>> collect = getAuthors().stream()
                .collect(Collectors.toMap(author -> author.getName(), author -> author.getBookList()));
        System.out.println("collect map = " + collect);
    }

匹配相关

anyMatch

可以用来判断是否有任意符合匹配条件的元素,结果为boolean类型

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

    //例子:判断是否有年龄在29以上的作家
    private static void test17() {
        boolean b = getAuthors().stream()
                .anyMatch(author -> author.getAge() > 29);
        System.out.println("b = " + b);
    }

allMatch

可以用来判断是否都符合匹配条件,结果为boolean类型。如果结果都符合则为true,否则为false

例子:判断所有作家是否为成年人

    //例子:判断所有作家是否为成年人
    private static void test18() {
        boolean b = getAuthors().stream()
                .allMatch(author -> author.getAge() > 18);
        System.out.println("b = " + b);
    }

noneMatch

可以判断流中的元素是否都不符合匹配条件,如果都不符合结果为true,否则结果为false

例子:判断作家是否都没有超过100岁

    //例子:判断作家是否都没有超过100岁
    private static void test19() {
        boolean b = getAuthors().stream()
                .noneMatch(author -> author.getAge() >= 100);
        System.out.println("b = " + b);
    }

查找相关

findAny

获取流中的任意一个元素,该方法没有办法保证获取的一定是流中的第一个元素。

例子:获取任意一个大于18的作家,如果存在就输出他的名字

    //例子:获取任意一个大于18的作家,如果存在就输出他的名字
    private static void test20() {
        Optional<Author> any = getAuthors().stream()
                .filter(author -> author.getAge()>18)
                .findAny();
        any.ifPresent((Author author) ->{       //如果存在   执行方法体中方法,避免空指针问题
            System.out.println(author.getName());
        });
    }

findFirst

获取流中的第一个元素

例子:获取一个年龄最小的作家,并输出他的姓名。

    //例子:获取一个年龄最小的作家,并输出他的姓名。
    private static void test21() {
        getAuthors().stream()
                .sorted((o1,o2) -> o1.getAge()-o2.getAge())
                .map(author -> author.getName())
                .findFirst()
                .ifPresent(System.out::println);
    }

reduce归并(难点)

对流中的数据按照你指定的计算方式计算出一个结果。(多个变成一个 -> 缩减操作)

reduce的作用是把stream中的元素给组合起来,我们可以传入一个初始值,它会按照我们的计算方式依次拿流中的元素合初始化值进行计算,计算结果在和后面的元素计算。

reduce两个参数的重载形式内部计算方式:

上述内部操作理解:

reduce相当于是将以上操作进行了抽取

例子:求所有作者的年龄和

    //例子:求所有作者的年龄和
    private static void test22() {
        Integer reduce = getAuthors().stream()
                .map(author -> author.getAge())//map reduce组合
                .distinct()
                .reduce(0, (result, integer2) -> result + integer2);
        System.out.println("reduce = " + reduce);
    }

例子:使用reduce求所有作者中年龄最大的 (前面的max/min方法底层实际就是使用的reduce方法)

    //例子:使用reduce求所有作者中年龄最大的
    private static void test23() {
        Integer reduce = getAuthors().stream()
                .map(Author::getAge)
                .reduce(Integer.MIN_VALUE, (result, integer) -> result = result < integer ? integer : result);
        System.out.println("reduce max = " + reduce);
    }

例子:使用reduce求所有作者中年龄最小值

    //例子:使用reduce求所有作者中年龄最小值
    private static void test24() {
        Integer reduce = getAuthors().stream()
                .map(Author::getAge)
                .reduce(Integer.MAX_VALUE, new BinaryOperator<Integer>() {
                    @Override
                    public Integer apply(Integer integer, Integer integer2) {
                        return integer < integer2 ? integer : integer2;
                    }
                });

        Integer reduce1 = getAuthors().stream()
                .map(author -> author.getAge())
                .reduce(Integer.MAX_VALUE, (result, integer) -> result < integer ? result : integer);

        System.out.println(reduce);
        System.out.println(reduce1);

    }

reduce单个参数的重载方法

//来自jdk源码
			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();

如果使用单个参数的重载方法,就无需传入初始值,原因看源码可得,如果是第一次进来该方法会将第一个值赋值为初始值

    //优化后代码为:取最大值
    private static void test25() {
        getAuthors().stream()
                .map(Author::getAge)
                .reduce((result, element) -> result > element ? result : element).ifPresent(a -> System.out.println(a));
        //System.out.println("reduce max2 = " + integer);
    }

reduce三个参数的重载方法会涉及到并行流,详细后面说明

3.5、Stream使用的注意事项

1、惰性求值,如果没有终结操作,中间操作是不会得到执行

2、流是一次性的,一旦一个流对象经过一个终结操作后,这个流不能再被使用

3、不回影响原数据,流中可以多数据做很多处理,但不回影响原来集合中的元素

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值