Java 8 Stream 闪亮登场!

    科技2026-08-17  11

    点击上方“Java基基”,选择“设为星标”

    做积极的人,而不是积极废人!

    源码精品专栏

     

    原创 | Java 2020 超神之路,很肝~

    中文详细注释的开源项目

    RPC 框架 Dubbo 源码解析

    网络应用框架 Netty 源码解析

    消息中间件 RocketMQ 源码解析

    数据库中间件 Sharding-JDBC 和 MyCAT 源码解析

    作业调度中间件 Elastic-Job 源码解析

    分布式事务中间件 TCC-Transaction 源码解析

    Eureka 和 Hystrix 源码解析

    Java 并发源码

    来源:cnblogs.com/funnyzpc/p/10382053.html

    一. Stream(流)是什么,干什么

    二. Stream操作方式

    三. Stream优势

    四. Stream(流)的基本使用


    一. Stream(流)是什么,干什么

      Stream是一类用于替代对集合操作的工具类+Lambda式编程,他可以替代现有的遍历、过滤、求和、求最值、排序、转换等

    二. Stream操作方式

    并行方式parallelStream

    顺序方式Stream

    三. Stream优势

    Lambda 可有效减少冗余代码,减少开发工作量

    内置对集合List、Map的多种操作方式,含基本数据类型处理

    并行Stream有效率优势(内置多线程)

    四. Stream(流)的基本使用

    遍历forEach

        @Test     public void stream() {         //操作List         List<Map<String, String>> mapList = new ArrayList() {             {                 Map<String, String> m = new HashMap();                 m.put("a", "1");                 Map<String, String> m2 = new HashMap();                 m2.put("b", "2");                 add(m);                 add(m2);             }         };         mapList.stream().forEach(item-> System.out.println(item));         //操作Map         Map<String,Object> mp = new HashMap(){             {                 put("a","1");                 put("b","2");                 put("c","3");                 put("d","4");             }         };         mp.keySet().stream().forEachOrdered(item-> System.out.println(mp.get(item)));     }

    过滤filter

              List<Integer> mapList = new ArrayList() {           {               add(1);               add(10);               add(12);               add(33);               add(99);           }       };      //mapList.stream().forEach(item-> System.out.println(item));       mapList = mapList.stream().filter(item->{           return item>30;       }).collect(Collectors.toList());       System.out.println(mapList);

    转换map和极值

        @Test   public void trans(){       List<Person> ps = new ArrayList<Person>(){           {               Person p1 = new Person();               p1.setAge(11);               p1.setName("张强");               Person p2 = new Person();               p2.setAge(17);               p2.setName("李思");               Person p3 = new Person();               p3.setAge(20);               p3.setName("John");               add(p1);               add(p2);               add(p3);           }       };       //取出所有age字段为一个List       List<Integer> sumAge = ps.stream().map(Person::getAge).collect(Collectors.toList());       System.out.println(sumAge);       //取出age最大的那       Integer maxAge =sumAge.stream().max(Integer::compare).get();       System.out.println(maxAge);   }   class Person{   private String name;   private Integer age;   public String getName() {       return name;   }   public void setName(String name) {       this.name = name;   }   public Integer getAge() {       return age;   }   public void setAge(Integer age) {       this.age = age;   }

    }

    #  五. Stream(流)的效率 + 模拟非耗时简单业务逻辑 class Person{ private String name; private int age; private Date joinDate; private String label; public String getName() {     return name; } public void setName(String name) {     this.name = name; } public int getAge() {     return age; } public void setAge(int age) {     this.age = age; } public Date getJoinDate() {     return joinDate; } public void setJoinDate(Date joinDate) {     this.joinDate = joinDate; } public String getLabel() {     return label; } public void setLabel(String label) {     this.label = label; }

    public class DataLoopTest { private static final Logger LOG= LoggerFactory.getLogger(DataLoopTest.class);

    private static final List<Person> persons = new ArrayList<>(); static {     for(int i=0;i<=1000000;i++){         Person p = new Person();         p.setAge(i);         p.setName("zhangSan");         p.setJoinDate(new Date());         persons.add(p);     } } /**  * for 循环耗时 ===> 1.988  * for 循环耗时 ===> 2.198  * for 循环耗时 ===> 1.978  *  */ @Test public void forTest(){     Instant date_start = Instant.now();     int personSize = persons.size();     for(int i=0;i<personSize;i++){         persons.get(i).setLabel(persons.get(i).getName().concat("-"+persons.get(i).getAge()).concat("-"+persons.get(i).getJoinDate().getTime()));     }     Instant date_end = Instant.now();     LOG.info("for 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0); } /**  *  forEach 循环耗时 ===> 1.607  *  forEach 循环耗时 ===> 2.242  *  forEach 循环耗时 ===> 1.875  */ @Test public void forEach(){     Instant date_start = Instant.now();     for(Person p:persons){         p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));     }     Instant date_end = Instant.now();     LOG.info("forEach 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0); } /**  *  streamForeach 循环耗时 ===> 1.972  *  streamForeach 循环耗时 ===> 1.969  *  streamForeach 循环耗时 ===> 2.125  */ @Test public void streamForeach(){     Instant date_start = Instant.now();     persons.stream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));     Instant date_end = Instant.now();     LOG.info("streamForeach 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0); } /**  *  parallelStreamForeach 循环耗时 ===> 1.897  *  parallelStreamForeach 循环耗时 ===> 1.942  *  parallelStreamForeach 循环耗时 ===> 1.642  */ @Test public void parallelStreamForeach(){     Instant date_start = Instant.now();     persons.parallelStream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));     Instant date_end = Instant.now();     LOG.info("parallelStreamForeach 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0); }

    }

    +  模拟耗时简单业务逻辑

    public class DataLoopBlockTest { private static final Logger LOG= LoggerFactory.getLogger(DataLoopTest.class);

    private static final List<Person> persons = new ArrayList<>(); static {     for(int i=0;i<=100000;i++){         Person p = new Person();         p.setAge(i);         p.setName("zhangSan");         p.setJoinDate(new Date());         persons.add(p);     } } /**  * for 循环耗时 ===> 101.385  * for 循环耗时 ===> 102.161  * for 循环耗时 ===> 101.472  *  */ @Test public void forTest(){     Instant date_start = Instant.now();     int personSize = persons.size();     for(int i=0;i<personSize;i++){         try {             Thread.sleep(1);             persons.get(i).setLabel(persons.get(i).getName().concat("-"+persons.get(i).getAge()).concat("-"+persons.get(i).getJoinDate().getTime()));         }catch (Exception e){             e.printStackTrace();         }     }     Instant date_end = Instant.now();     LOG.info("for 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0); } /**  *  forEach 循环耗时 ===> 101.027  *  forEach 循环耗时 ===> 102.488  *  forEach 循环耗时 ===> 101.608  */ @Test public void forEach(){     Instant date_start = Instant.now();     for(Person p:persons){         try {             Thread.sleep(1);             p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));         }catch (Exception e){             e.printStackTrace();         }     }     Instant date_end = Instant.now();     LOG.info("forEach 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0); } /**  *  streamForeach 循环耗时 ===> 103.246  *  streamForeach 循环耗时 ===> 101.128  *  streamForeach 循环耗时 ===> 102.615  */ @Test public void streamForeach(){     Instant date_start = Instant.now();     //persons.stream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));     persons.stream().forEach(p->{         try {             Thread.sleep(1);             p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));         }catch (Exception e){             e.printStackTrace();         }     });     Instant date_end = Instant.now();     LOG.info("streamForeach 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0); } /**  *  parallelStreamForeach 循环耗时 ===> 51.391  *  parallelStreamForeach 循环耗时 ===> 53.509  *   parallelStreamForeach 循环耗时 ===> 50.831  */ @Test public void parallelStreamForeach(){     Instant date_start = Instant.now();     //persons.parallelStream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));     persons.parallelStream().forEach(p->{         try {             Thread.sleep(1);             p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));         }catch (Exception e){             e.printStackTrace();         }     });     Instant date_end = Instant.now();     LOG.info("parallelStreamForeach 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0);     //LOG.info("\r\n===> {}",JSON.toJSONString(persons.get(10000))); }

    }

    可以看到在百万数据下做简单数据循环处理,对于普通for(for\foreach)循环或stream(并行、非并行)下,几者的效率差异并不明显, 注意: 在百万数据下,普通for、foreach循环处理可能比stream的方式快许多,对于这点效率的损耗,其实lambda表达式对代码的简化更大!另外,在并行流的循环下速度提升了一倍之多,当单个循环耗时较多时,会拉大与前几者的循环效率 (以上测试仅对于循环而言,其他类型业务处理,比如排序、求和、最大值等未做测试,个人猜测与以上测试结果相似)

    # 六. Stream(流)注意项 + 并行stream不是线程安全的,当对循坏外部统一对象进行读写时候会造成意想不到的错误,这需要留意 + 因stream总是惰性的,原对象是不可以被修改的,在集合处理完成后需要将处理结果放入一个新的集合容器内 + 普通循环与stream(非并行)循环,在处理处理数据量比较大的时候效率是一致的,推荐使用stream的形式 + 对于List删除操作,目前只提供了removeIf方法来实现,并不能使用并行方式 + 对于lambda表达式的写法 -  当表达式内只有一个返回boolean类型的语句时候语句是可以简写的,例如:

    persons.parallelStream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));

    - 当表达式内会有一些复杂处理逻辑时需要加上大括号,这与初始化List参数方式大致一致     persons.parallelStream().forEach(p->{         try {             Thread.sleep(1);             p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));         }catch (Exception e){             e.printStackTrace();         }     }); # 七. stream&Lambda表达式常用api方法 +  流到流之间的转换类     -  filter(过滤)     - map(映射转换)     - mapTo[Int|Long|Double] (到基本类型流的转换)     - flatMap(流展开合并)     - flatMapTo[Int|Long|Double]     - sorted(排序)     - distinct(不重复值)     - peek(执行某种操作,流不变,可用于调试)     - limit(限制到指定元素数量)     - skip(跳过若干元素) +  流到终值的转换类     - toArray(转为数组)     - reduce(推导结果)     - collect(聚合结果)     - min(最小值)     - max(最大值)     - count (元素个数)     - anyMatch (任一匹配)     - allMatch(所有都匹配)     - noneMatch(一个都不匹配)     - findFirst(选择首元素)     - findAny(任选一元素) + 直接遍历类     - forEach (不保证顺序遍历,比如并行流)     - forEachOrdered(顺序遍历) + 构造流类     - empty (构造空流)     - of (单个元素的流及多元素顺序流)     - iterate (无限长度的有序顺序流)     - generate (将数据提供器转换成无限非有序的顺序流)     - concat (流的连接)     - Builder (用于构造流的Builder对象)

    欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:

    已在知识星球更新源码解析如下:

    最近更新《芋道 SpringBoot 2.X 入门》系列,已经 20 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

    提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

    获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

    Processed: 0.009, SQL: 9