前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Stream闪亮登场

Stream闪亮登场

作者头像
上帝
发布2019-03-04 10:57:34
4460
发布2019-03-04 10:57:34
举报
文章被收录于专栏:影子影子

Stream闪亮登场

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

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

二. Stream操作方式
  • 并行方式parallelStream
  • 顺序方式Stream
三. Stream优势
  • Lambda 可有效减少冗余代码,减少开发工作量
  • 内置对集合List、Map的多种操作方式,含基本数据类型处理
  • 并行Stream有效率优势(内置多线程)
四. Stream(流)的基本使用
  • 遍历forEach
代码语言:javascript
复制
    @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
代码语言:javascript
复制
          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和极值
代码语言:javascript
复制

     @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) {       
    his.age = age;   
}  
}

五. Stream(流)的效率

  • 模拟非耗时简单业务逻辑
代码语言:javascript
复制
    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);
    }

}
  • 模拟耗时简单业务逻辑
代码语言:javascript
复制
  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)));
    }
}

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

六. Stream(流)注意项
  • 并行stream不是线程安全的,当对循坏外部统一对象进行读写时候会造成意想不到的错误,这需要留意
  • 因stream总是惰性的,原对象是不可以被修改的,在集合处理完成后需要将处理结果放入一个新的集合容器内
  • 普通循环与stream(非并行)循环,在处理处理数据量比较大的时候效率是一致的,推荐使用stream的形式
  • 对于List删除操作,目前只提供了removeIf方法来实现,并不能使用并行方式
  • 对于lambda表达式的写法
  • 当表达式内只有一个返回boolean类型的语句时候语句是可以简写的,例如:
代码语言:javascript
复制
 persons.parallelStream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));
  • 当表达式内会有一些复杂处理逻辑时需要加上大括号,这与初始化List参数方式大致一致
代码语言:javascript
复制
        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对象)
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-02-16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Stream闪亮登场
    • 一. Stream(流)是什么,干什么
      • 二. Stream操作方式
        • 三. Stream优势
          • 四. Stream(流)的基本使用
            • 六. Stream(流)注意项
              • 七. stream&Lambda表达式常用api方法
              相关产品与服务
              容器服务
              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档