Skip to content

【Java8】Stream 常用场景 #9

Open
@0xbitboy

Description

@0xbitboy

Java8 中的新特性提供了Stream的API,Stream顾名思义,就是流,也就是说我们可以流式处理java中的集合类了,用传统的方式可能对集合的一个或者多个操作要写很多额外的代码,而stream只需要一行搞定,正是个原因,你会发现stream通常会出现在各大it问答网站的“一行实现xxxx”的问题中。Stream 在相对与传统的集合操作方式来说确实有性能损失,除了对性能要求特别高的业务外,从代码简洁可维护性的角度看,还是非常推荐使用的。

Stream 中的API分两种 一种是intermediate(中间操作),另外一种是 terminal (终止操作), 从collection.stream()开始,可以进行多次的intermediate的api调用,就像流一样,从一端一直流到另外一端,这个水管不会堵住,也不会往回流。terminal操作是stream的终止操作,也是流开始处理的调用起点。换个角度说就是,intermediate的api调用只不过是在构造流处理器,好比在给流接水管,这个时候水龙头还没开阀门。当我们执行一个terminal 操作的时候,开水阀,开始接水处理。也就是可以认为我们在一行执行的stream操作,其实只会执行一个O(N)复杂度的算法。

类型 操作
间接 filter,map,flatmap,peek,distinct,sorted,limit
终止 forEach ,toArray,reduce,collect,min,max,count,anymatch,allMatch,noneMatch,findAny
  • List to Map

通常我们在写业务的时候,有很多数据并不需要每次都去查数据库或者redis,所以会在服务启动的时候,将数据加载到堆内存,通常我们会在数据库会读出一个列表,而很多时候我们读信息都是根据主键去查,所以就需要List to Map的操作,这个用Stream API 是非常方便的。


public class PrizePO{
    
    private Long prizeId;
    private String prizeName;
    private Long activityId;
    private Integer sequnce;
    private Integer price; 
    //....other 
    
    //getter ...
    public Long getPrizeId(){return prizeId;}
    
}

//
List<PrizePO>  prizeListInDb = PrizeDao.listAll();
// Function.identity() 等价与 t->t 
Map<Long,PrizePO> prizeCache = prizeListInDb.stream().collect(Collectors.toMap(PrizePO::getQuizId,Function.identity()));

上面的方式只有key唯一的时候才行,当你指定的key存在重复的情况下怎么办呢?

//实际上 Collectors.toMap 有第三个参数,可以传一个mergeFunction,当存在重复时执行。
//(a,b)->a 的意思就是 当存在重复元素时用旧的代替
Map<Long,PrizePO> prizeCache = prizeListInDb.stream().collect(Collectors.toMap(PrizePO::getQuizId,Function.identity(),(a,b)->a));
  • List分组

拿上面那个奖品的例子说,上面的可能是一个活动奖品,但是我们的设计可能是可以同时支持多个活动的,那么我们的缓存可能就要再改下了,除了要根据奖品Id去取奖品信息外,我们可能要根据活动ID去取这个活动下的所有奖品列表。所以我们需要对数据库读取出来的列表进行一个分组,我们最终需要的是一个Map<Long,List> 的结构

Map<Long, List<PrizePO>> activityPrizeCache = prizePOList.stream().collect(Collectors.groupingBy(PrizePO::getActivityId));

  • List 排序
// 根据顺序号进行排序
List<PrizePO> sortBySeq = prizePOList.stream().sorted(Comparator.comparing(PrizePO::getSequence)).collect(Collectors.toList());
// 根据顺序号进行排序,再按价格进行排序,相当于 order by sequence,price
List<PrizePO> sortBySeqAndPrice  = prizePOList.stream().sorted(Comparator.comparing(PrizePO::getSequence).thenComparing(PrizePO::getPrice)).collect(Collectors.toList());

  • List 求和
// 对 price 字段求和
int sum = prizePOList.stream().mapToInt(PrizePO::getPrice).sum();

  • List<A> to List<B>

这个场景也是非常常见的,比如构造查询条件,通常需要从A列表中去构造B列表,或者返回结果中,需要从一个PO转换成一个DTO。

 public static class PrizeDTO{
     
     private prizeName;
     
     // ...other
     
 }
 
 List<PrizeDTO> prizeDtoList = prizePoList.stream().map(prizePO->new PrizeDTO(prizePO)).collect(Collectors.toList());
 
     

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions