JDK1.8 Java8 Stream流 认知以及常见使用

注意前提条件: 环境一定是JDK1.8

现在大部分都是1.8的环境,同样也要学习、使用、对其认知,可以使我们开发效率提高,不至于别人请教的时候不清楚。

/**
 * @ClassName User
 * @Description 用户
 * @Author QiMing
 * @Date 2021/3/27 8:46
 * @Version 1.0
 */
@Data
public class User {

    private long id;

    /**
     * 名字
     */
    private String name;

    /**
     * 年龄
     */
    private int age;

    /**
     * 邮箱
     */
    private String email;

    /**
     * 爱好
     */
    private String hobby;

    public User(){
        super();
    }

    public User(long id, String name, int age, String email, String hobby) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.email = email;
        this.hobby = hobby;
    }
}
/**
     * @Title: main
     * @Description: // 测试使用Stream
     * @Param: [args]
     * @Return: void
     * @Date: 2021/3/27 9:00
     * @Author: QiMing
     */
    public static void main(String[] args) {
        List<User> users = Lists.newArrayList();
        users.add(new User(1, "大宝", 26, "1234@qq.com", "插花"));
        users.add(new User(2, "二宝", 24, "2345@qq.com", "茶艺"));
        users.add(new User(3, "三宝", 24, "3456@qq.com", "学习"));
        users.add(new User(4, "四宝", 20, "4567@qq.com", "旅行"));
        users.add(new User(5, "五宝", 18, "5678@qq.com", "健身"));
        users.add(new User(6, "小宝", 5, "6789@qq.com", "画画"));
        users.add(new User(7, "baby", 18, "7890@qq.com", "美妆"));


        users.stream().forEach((User u) -> {
            // 年龄等于18的 email 设置空
            if (18 == u.getAge()) {
                u.setEmail(null);
            }
        });
        // Lambda 遍历
        users.forEach((User u) -> {
            System.out.println(u);
        });

        System.out.println("双冒号格式");
        users.forEach(System.out::println);
        /**
         * 执行结果:
         * 双冒号格式
         * User(id=1, name=大宝, age=26, email=1234@qq.com, hobby=插花)
         * User(id=2, name=二宝, age=24, email=2345@qq.com, hobby=茶艺)
         * User(id=3, name=三宝, age=24, email=3456@qq.com, hobby=学习)
         * User(id=4, name=四宝, age=20, email=4567@qq.com, hobby=旅行)
         * User(id=5, name=五宝, age=18, email=null, hobby=健身)
         * User(id=6, name=小宝, age=5, email=6789@qq.com, hobby=画画)
         * User(id=7, name=baby, age=18, email=null, hobby=美妆)
         */

        // Lambda 简化了代码,但减少了代码的可读性

        /**
         * Stream
         * Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
         * Stream API可以极大提高我们的效率,开发过程中写出高效率、干净、简洁的代码。
         * 这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
         *
         * 特性:
         * 1.不是数据结构:它没有内部存储,它只是用操作管道从source(数据结构、数组、generator function、IO channel)抓取数据。
         * 它也绝不修改自己所封装的底层数据结构。例如 Stream的filter 操作产生一个不包含被过滤元素的新Stream,而不是source删除那些元素。
         * 2.不支持索引访问:但是很容易生成数组或者 List 。
         * 3.惰性化:很多 Stream 操作是向后延迟的,一直到它弄清楚了最后需要多少数据才会开始。Intermediate 操作永远是惰性化的。
         * 4.并行能力。当一个 Stream 是并行化的,就不需要再写多线程代码,所有对它的操作会自动并行进行的。
         * 5.可以是无限的:集合有固定大小,Stream 则不必。limit(n) 和 findFirst() 这类的 short-circuiting 操作可以对无限的 Stream 进行运算并很快完成。
         *
         * 注意:所有Stream 的操作必须以lambda 表达式为参数。
         *
         * Stream 流操作类型:
         * 1.ntermediate:一个流可以后面跟随零个或多个 intermediate 操作。
         * 其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。
         * 2.Terminal:一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。
         * 所以这必定是流的最后一个操作。Terminal操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。
         */

        /**
         * Stream 过滤示例
         * 在没使用Stream之前 我们一般采用 for 循环过滤,处理数据繁琐
         */

        System.out.println("未过滤的数据   ---" + users);
        // 执行结果: 未过滤的数据   ---[User(id=1, name=大宝, age=26, email=1234@qq.com, hobby=插花), User(id=2, name=二宝, age=24, email=2345@qq.com, hobby=茶艺), User(id=3, name=三宝, age=24, email=3456@qq.com, hobby=学习), User(id=4, name=四宝, age=20, email=4567@qq.com, hobby=旅行), User(id=5, name=五宝, age=18, email=null, hobby=健身), User(id=6, name=小宝, age=5, email=6789@qq.com, hobby=画画), User(id=7, name=baby, age=18, email=null, hobby=美妆)]

        // for循环过滤
        List<User> list = Lists.newArrayList();
        for (User user : users) {
            if (24 != user.getAge()) {
                list.add(user);
            }
        }
        System.out.println("for过滤之后的数据   ---" + list);
        // 执行结果: for过滤之后的数据   ---[User(id=1, name=大宝, age=26, email=1234@qq.com, hobby=插花), User(id=4, name=四宝, age=20, email=4567@qq.com, hobby=旅行), User(id=5, name=五宝, age=18, email=null, hobby=健身), User(id=6, name=小宝, age=5, email=6789@qq.com, hobby=画画), User(id=7, name=baby, age=18, email=null, hobby=美妆)]

        // Stream 方式
        List<User> collect = users.stream().filter((User u) ->
                (24 != u.getAge())).collect(Collectors.toList());
        System.out.println("Stream 过滤后的数据  ---" + collect);
        // 执行结果: Stream 过滤后的数据  ---[User(id=1, name=大宝, age=26, email=1234@qq.com, hobby=插花), User(id=4, name=四宝, age=20, email=4567@qq.com, hobby=旅行), User(id=5, name=五宝, age=18, email=null, hobby=健身), User(id=6, name=小宝, age=5, email=6789@qq.com, hobby=画画), User(id=7, name=baby, age=18, email=null, hobby=美妆)]


        /**
         * Stream 流之间的转换
         * 注意一个Stream流只可以使用一次,这段代码为了简洁而重复使用了数次,
         * 因此会抛出 stream has already been operated upon or closed 异常。
         */
        try {
            Stream stream = Stream.of("say", "hello", "world");
            // 转换数组
            Object[] objects = stream.toArray(String[]::new);

            // 转换成 Collection
            List list1 = (List) stream.collect(Collectors.toList());
            List list2 = (List) stream.collect(Collectors.toCollection(ArrayList::new));
            Set set = (Set) stream.collect(Collectors.toSet());

            // 转换成String
            String toString = stream.collect(Collectors.joining()).toString();
        } catch (Exception e) {
            e.printStackTrace();
        }

        /**
         * Stream 流的map使用
         */
        // 转换大写
        List<String> stringList = Arrays.asList("java", "php", "vue");
        System.out.println("stringList转换之前" + stringList);
        // 执行结果: stringList转换之前[java, php, vue]

        List<String> stringList1 = stringList.stream().map(String::toUpperCase).collect(Collectors.toList());
        System.out.println("stringList转换之后" + stringList1);
        // 执行结果: stringList转换之后[JAVA, PHP, VUE]

        // 转换数据类型
        List<String> stringList2 = Arrays.asList("1", "2", "3");
        System.out.println("转换之前的数据:" + stringList2);
        // 执行结果: 转换之后的数据:[1, 2, 3]
        List<Integer> integerList = stringList2.stream().map(Integer::valueOf).collect(Collectors.toList());
        System.out.println("转换之后的数据:" + integerList);
        // 执行结果: 转换之后的数据:[1, 2, 3]

        // 获取平方
        List<Integer> squares = Arrays.asList(new Integer[]{1, 2, 3, 4, 5});
        List<Integer> squareList = squares.stream().map(n -> (n * n)).collect(Collectors.toList());
        System.out.println("平方的数据:" + squareList);
        /**
         * 执行结果:平方的数据:[1, 4, 9, 16, 25]
         */

        /**
         * Stream流的filter使用
         * filter方法用于通过设置的条件过滤出元素。
         * 通过与 findAny 得到 if/else 的值
         */
        List<String> names = Arrays.asList("张三", "李四", "王二", "麻子");
        String filter1 = names.stream().filter(str -> "李四".equals(str)).findAny().orElse("找不到!");
        String filter2 = names.stream().filter(str -> "baby".equals(str)).findAny().orElse("找不到!");

        System.out.println("stream 过滤之后 1:" + filter1);
        System.out.println("stream 过滤之后 2:" + filter2);
        /**
         * 执行结果:
         * stream 过滤之后 1:李四
         * stream 过滤之后 2:找不到!
         */

        // 年龄不等于24的年龄总和
        int sum = users.stream().filter((User u) -> 24 != u.getAge()).mapToInt(u -> u.getAge()).sum();
        System.out.println("年龄不等于24的年龄总和" + sum);
        // 执行结果: 年龄不等于24的年龄总和87

        /**
         * Stream流的flatMap使用
         * flatMap 方法用于映射每个元素到对应的结果,一对多。
         * 从句子中得到单词
         */
        String words = "You look perfect";
        List<String> wordsList = Lists.newArrayList();
        wordsList.add(words);

        List<String> collect1 = wordsList.stream().flatMap(str -> Stream.of(str.split(" "))).filter(word -> word.length() > 0).collect(Collectors.toList());
        System.out.println("单词: ");
        collect1.forEach(System.out::println);
        /**
         * 执行结果:
         * You
         * look
         * perfect
         */

        /**
         * Stream流的limit使用
         * limit 方法用于获取指定数量的流。
         * 获取前n条数的数据
         */
        Random rd = new Random();
        System.out.println("取到的前四条数据:");
        rd.ints().limit(4).forEach(System.out::println);
        /**
         * 执行结果:
         * 240251717
         * -119437735
         * 786951197
         * -966403468
         */

        // 结合skip使用得到需要的数据
        // skip表示的是扔掉前n个元素
        // 取前3条数据,但是扔掉了前面的2条,可以理解为拿到的数据为 2<=i<3 (i 是数值下标)
        List<String> stringList3 = users.stream().map(User::getName).limit(3).skip(2).collect(Collectors.toList());
        System.out.println("截取之后的数据:" + stringList3);
        // 执行结果: 截取之后的数据:[三宝]

        /**
         * Stream流的sort使用
         * sorted方法用于对流进行升序排序。
         * 随机取值排序
         */
        rd.ints().limit(3).sorted().forEach(System.out::println);
        /**
         *  执行结果:
         * -818868489
         * -634087012
         * -464860067
         */

        // tips:先获取在排序效率会更高!
        // 普通排序
        List<User> collect2 = users.stream().sorted((u1, u2) -> u1.getName().compareTo(u2.getName())).limit(3).collect(Collectors.toList());
        System.out.println("排序数据:" + collect2);

        // 优化排序取值
        List<User> collect3 = users.stream().limit(3).sorted((u1, u2) -> u1.getName().compareTo(u2.getName())).collect(Collectors.toList());
        System.out.println("优化后的排序" + collect3);


        /**
         * Stream流的peek使用
         * peek对每个元素执行操作并返回一个新的Stream
         * 双重操作
         */
        System.out.println("peek使用:");
        Stream.of("one", "two", "three", "four").filter(e -> e.length() > 3).peek(e -> System.out.println("转换之前: " + e))
                .map(String::toUpperCase).peek(e -> System.out.println("转换之后: " + e)).collect(Collectors.toList());
        /**
         * 执行结果:
         * 转换之前: three
         * 转换之后: THREE
         * 转换之前: four
         * 转换之后: FOUR
         */

        /**
         * Stream流的parallel使用
         * parallelStream 是流并行处理程序的代替方法。
         * 示例:获取空字符串的数量
         */
        List<String> strings = Arrays.asList("a", "", "c", "", "e", "", " ");
        // 获取空字符串的数量
        long count = strings.parallelStream().filter(string -> string.isEmpty()).count();
        System.out.println("空字符串的个数:" + count);
        // 执行结果: 空字符串的个数:3

        /**
         * Stream流的max/min/distinct使用
         */
        // 得到最大值 最小值
        List<String> names1 = Arrays.asList("zhangsan", "lisi", "wanger", "mazi");
        int maxLines = names1.stream().mapToInt(String::length).max().getAsInt();
        int minLines = names1.stream().mapToInt(String::length).min().getAsInt();
        System.out.println("最长字符的长度:" + maxLines + ",最短字符的长度:" + minLines);
        // 执行结果: 最长字符的长度:8,最短字符的长度:4

        // 得到去重之后的数据
        String lines = "she say hello say hello";
        List<String> list14 = new ArrayList();
        list14.add(lines);
        List<String> wordLists = list14.stream().flatMap(line -> Stream.of(line.split(" "))).filter(word -> word.length() > 0)
                .map(String::toLowerCase).distinct().sorted().collect(Collectors.toList());
        System.out.println("去重复之后:" + wordLists);
        // 执行结果: 去重复之后:[hello, say, she]

        // 对象某一个值去重
        List<Integer> collect4 = users.stream().map(User::getAge).distinct().collect(Collectors.toList());
        System.out.println(collect4);
        // 执行结果: [26, 24, 20, 18, 5]
        List<User> userList = users.stream().collect(
                Collectors.collectingAndThen(
                        Collectors.toCollection(
                                () -> new TreeSet<>(
                                        // 这里根据对象的某一个值去重,也可以根据多个 在u.getAge()追加 例如u.getAge()+u.getName()
                                        Comparator.comparing((User u) -> u.getAge()
                                        )
                                )
                        ),
                        ArrayList::new)
        );
        System.out.println(userList);
        // 执行结果: [User(id=6, name=小宝, age=5, email=6789@qq.com, hobby=画画), User(id=5, name=五宝, age=18, email=null, hobby=健身), User(id=4, name=四宝, age=20, email=4567@qq.com, hobby=旅行), User(id=2, name=二宝, age=24, email=2345@qq.com, hobby=茶艺), User(id=1, name=大宝, age=26, email=1234@qq.com, hobby=插花)]

        /**
         * Stream流的Match使用
         * allMatch:Stream 中全部元素符合则返回 true ;
         * anyMatch:Stream 中只要有一个元素符合则返回 true;
         * noneMatch:Stream 中没有一个元素符合则返回 true。
         */
        boolean all = users.stream().allMatch(u -> u.getId() > 3);
        System.out.println("是否都大于3:" + all);
        boolean any = users.stream().anyMatch(u -> u.getId() > 3);
        System.out.println("是否有一个大于3:" + any);
        boolean none = users.stream().noneMatch(u -> u.getId() > 3);
        System.out.println("是否没有一个大于3的:" + none);

        /**
         * 执行结果:
         * 是否都大于3:false
         * 是否有一个大于3:true
         * 是否没有一个大于3的:false
         */

        /**
         * Stream流的reduce使用
         * reduce 主要作用是把 Stream 元素组合起来进行操作。
         * 字符串连接
         */
        String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
        System.out.println("字符串拼接:" + concat);
        // 执行结果: 字符串拼接:ABCD

        // 得到最小值
        double minValue = Stream.of(-6.0, 1.0, 3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);
        System.out.println("最小值:" + minValue);
        // 执行结果: 最小值:-6.0

        // 求和
        // 求和, 无起始值
        int sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
        System.out.println("有无起始值求和:" + sumValue);
        // 执行结果: 有无起始值求和:10

        // 求和, 有起始值
        sumValue = Stream.of(1, 2, 3, 4).reduce(5, Integer::sum);
        System.out.println("有起始值求和:" + sumValue);
        // 执行结果: 有起始值求和:15

        // 过滤拼接
        String filterConcat = Stream.of("a", "B", "c", "D", "e", "F").
                filter(x -> x.compareTo("Z") > 0).reduce("", String::concat);
        System.out.println("过滤和字符串连接:" + filterConcat);
        // 执行结果: 过滤和字符串连接:ace

        /**
         * Stream流的iterate使用
         * “iterate 跟 reduce 操作很像,接受一个种子值,和一个UnaryOperator(例如 f)。
         * 然后种子值成为 Stream 的第一个元素,f(seed) 为第二个,f(f(seed)) 第三个,以此类推。
         * 在 iterate 时候管道必须有 limit 这样的操作来限制 Stream 大小。
         */
        // 生成一个等差队列
        Stream.iterate(2, n -> n + 2).limit(5).forEach(x -> System.out.print(x + " "));
        // 执行结果: 2 4 6 8 10
        System.out.println();

        // Stream groupingBy:分组
        // 根据年龄分组
        Map<Integer, List<User>> listMap = users.stream().collect(Collectors.groupingBy(User::getAge));

        Iterator<Map.Entry<Integer, List<User>>> iterator = listMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Integer, List<User>> mapEntry = iterator.next();
            System.out.println("age= " + mapEntry.getKey() + "value= " + mapEntry.getValue());
        }
        /**
         * 执行结果:
         * age= 18value= [User(id=5, name=五宝, age=18, email=null, hobby=健身), User(id=7, name=baby, age=18, email=null, hobby=美妆)]
         * age= 20value= [User(id=4, name=四宝, age=20, email=4567@qq.com, hobby=旅行)]
         * age= 5value= [User(id=6, name=小宝, age=5, email=6789@qq.com, hobby=画画)]
         * age= 24value= [User(id=2, name=二宝, age=24, email=2345@qq.com, hobby=茶艺), User(id=3, name=三宝, age=24, email=3456@qq.com, hobby=学习)]
         * age= 26value= [User(id=1, name=大宝, age=26, email=1234@qq.com, hobby=插花)]
         */

        /**
         * Stream流的summaryStatistics使用
         * IntSummaryStatistics 用于收集统计信息(如count、min、max、sum和average)的状态对象。
         * 得到最大、最小、之和以及平均数。
         */
        List<Integer> numbers = Arrays.asList(1, 8, 15, 21, 30);
        IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();

        System.out.println("列表中最大的数 : " + stats.getMax());
        System.out.println("列表中最小的数 : " + stats.getMin());
        System.out.println("所有数之和 : " + stats.getSum());
        System.out.println("平均数 : " + stats.getAverage());
        /**
         * 执行结果:
         * 列表中最大的数 : 30
         * 列表中最小的数 : 1
         * 所有数之和 : 75
         * 平均数 : 15.0
         */


        Integer ageSum = users.stream().collect(Collectors.summingInt((User u) -> u.getAge() < 0 ? 0 : u.getAge()));
        // u.getAge() < 0 ? 0 : u.getAge() 此处三目运算是为解决其他类型为null
        System.out.println("年龄小于0的年龄之和: " + ageSum);
        // 执行结果: 年龄小于0的年龄之和: 135

    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Stream是在Java 8之后新增的一个特性,它是用来操作集合(Collection)的工具。Stream提供了一种简洁、高效的方式来对集合进行处理和操作。Stream可以用于遍历集合的元素、进行过滤、映射、排序、聚合等各种操作。 在使用Stream时,常用的方法之一是forEach()方法,它用来遍历Stream的数据。这个方法是一个终结方法,一旦调用了forEach()方法,就不能再继续调用Stream的其他方法了。例如,下面的代码演示了如何使用forEach()方法遍历一个Stream并打印其的元素: ``` List<String> list = Arrays.asList("字节","网易","百度", "美团", "阿里", "字节"); Stream<String> stream = list.stream(); stream.forEach(System.out::println); ``` 执行以上代码会依次打印出集合的元素:"字节"、"网易"、"百度"、"美团"、"阿里"、"字节"。 除了forEach()方法之外,Stream还提供了许多其他常用的方法,比如filter()用于过滤元素、map()用于映射元素、sorted()用于排序元素、reduce()用于聚合元素等等。这些方法可以根据具体的需求来选择使用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [JDK1.8常见Stream](https://blog.csdn.net/TFHoney/article/details/129687717)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值