分享

java8关于Stream的一些实战经验、注意点!

 笑笑兔 2023-09-15

前言

文章中的观点,来源于博客中博主一些看法,本文只是验证整理内容。

一、Stream函数会循环多少次

示例代码:

List<String> ages = Stream.of(17,22,35,12,37)
                .filter(age -> {
                    System.out.println("filter1 处理:" + age);
                    return age > 18;
                })
                .filter(age -> {
                    System.out.println("filter2 处理:" + age);
                    return age < 35;
                })
                .map(age -> {
                    System.out.println("map 处理:" + age);
                    return age + "岁";
                })
                .collect(Collectors.toList());

运行结果:

filter1 处理:17
filter1 处理:22
filter2 处理:22
map 处理:22
filter1 处理:35
filter2 处理:35
filter1 处理:12
filter1 处理:37
filter2 处理:37

通过结果很明显看出,stream流处理的时候,只是对列表循环了一次,然后顺序执行待定的stream语句。

二、Idea断点调试Stream代码

  • Line:断点打在这一行上,不会进入到具体的Stream执行函数块中

  • Lambda:代码打在内部的lambda代码块上

  • Line and Lambda:代码走到这行或者执行这一行具体的函数块内容的时候,都会进入断点

选择第二项,lambda调试后可以看到变量值

大部分情况,掌握这种方式,可以应付日常开发遇到stream代码逻辑调试。如果想调试查看整个Stream代码执行变化过程,必须使用“TraceCurrentStreamChain”如图:

当debug运行调试时,断点必须打在Stream开流的地方 ,然后打”TraceCurrentStreamChain”面板,f8执行调试。效果如下:

通过调试,看到stream处理每个环节的结果。比如我们以 filter环节为例,窗口中以左右视图的形式,左侧显示了原始输入的内容,右侧是经过filter处理后符合条件并保留下来的数据内容。

三、Collectors.toMap关于key值重复报错

平时HashMap的 put(key,value)操作时,一般很不会在意key是否已在map中存在,它会覆盖已有的数据。Stream中,使用 Collectors.toMap方法来实现的时候,如果不判断,会报错。

示例代码:

 List<Student> personList = new ArrayList<Student>();
        personList.add(new Student("Tom", 8900, "male", "New York"));
        personList.add(new Student("Tom", 7000, "male", "Washington"));
        personList.add(new Student("Lily", 7800, "female", "Washington"));
        personList.add(new Student("Anni", 8200, "female", "New York"));
        personList.add(new Student("Owen", 9500, "male", "New York"));
        personList.add(new Student("Alisa", 7900, "female", "New York"));
        Map<String, Student> collectMap = personList.stream()
                .collect(Collectors.toMap(Student::getName, stu -> stu));
        System.out.println("collectMap:" + collectMap);

运行后发现报错:

Exception in thread "main" java.lang.IllegalStateException: Duplicate key com.project.demo.java8.Pojo.Student@42eca56e
	at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
	at java.util.HashMap.merge(HashMap.java:1256)

map转换的时候,出现了重复key,所以抛出异常。

那我们需要手动指定让toMap,按照我们的要求进行处理。

 Map<String, Student> collectMap = personList.stream()
                .collect(Collectors.toMap(Student::getName, stu -> stu,(exist,newStu)->newStu));
        System.out.println("collectMap:" + collectMap);

运行后正常打印。一般日常工作中,都是直接去重再进行转换。

四、不要用peek函数处理业务

  long count = personList.stream().peek(x -> log.info("peek:{}", JSONUtil.toJsonStr(x))).count();

查看peek源码,有说明大致意思,这个方法只是用于调试、日志打印。

五、Stream关于Collectors.join存在意义

一般字符串拼接,直接通过String.join可以了,但是遇到对象列表的字符串拼接,必须使用Collections.joining方法。

 List<Student> personList = new ArrayList<Student>();
        personList.add(new Student("Tom", 8900, "male", "New York"));
        personList.add(new Student("Tom", 7000, "male", "Washington"));
        personList.add(new Student("Lily", 7800, "female", "Washington"));
        personList.add(new Student("Anni", 8200, "female", "New York"));
        personList.add(new Student("Owen", 9500, "male", "New York"));
        personList.add(new Student("Alisa", 7900, "female", "New York")); 
String nameStrJoin = personList.stream().map(Student::getName).collect(Collectors.joining(","));
        log.info("nameStrJoin:{}", nameStrJoin);

运行结果:

 nameStrJoin:Tom,Tom,Lily,Anni,Owen,Alisa

总结

关于java8 Stream常用的方法还有很多,目前只是举例说明。遇到Stream流的断点调试,通过idea开发工具,能够更好、全面的监视运行情况。

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约