Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【Java8】Stream 常用场景 #9

Open
0xbitboy opened this issue Sep 30, 2019 · 0 comments
Open

【Java8】Stream 常用场景 #9

0xbitboy opened this issue Sep 30, 2019 · 0 comments

Comments

@0xbitboy
Copy link
Owner

0xbitboy commented Sep 30, 2019

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());
 
     
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant