四时宝库

程序员的知识宝库

JDK8中的Stream流(java的stream流)

JDK8中的Stream流

前言

jdk8版本,多出了很多很重要的特性。

其中最重要的Lambda和Stream能够让我们写出高效率、干净、简洁的代码。

本文目的是让大家更加轻松地学习并理解Stream流,能够应用到实际的项目中。

认识Stream流

  • 提取对象中的某个值生成一个新的List
Bash
 
 // 生成数据
 Map<String, String> arg1 = new HashMap<>();
 arg1.put("name", "dog");
 arg1.put("age", "3");
 
 
 Map<String, String> arg2 = new HashMap<>();
 arg2.put("name", "cat");
 arg2.put("age", "8");
 
 // 转换数据
 List<Integer> ageList = Stream.of(arg1, arg2)
   .map(map -> Integer.valueOf(map.get("age")))
   .collect(Collectors.toList());
 // ageList 为 3,8
  • 统计一个对象某个值的总和
Bash
 // 生成数据
 Map<String, String> arg1 = new HashMap<>();
 arg1.put("name", "dog");
 arg1.put("age", "3");
 
 Map<String, String> arg2 = new HashMap<>();
 arg2.put("name", "cat");
 arg2.put("age", "8");
 // Stream流统计年龄合计
 Optional<Integer> ageSum = Stream.of(arg1, arg2)
   .map(map -> Integer.valueOf(map.get("age")))// map 数据转换
   .reduce(Integer::sum);// 归约操作,Integer::sum 等价 (a,b)->a+b; 其中a为上次计算的结果,b为新的值,然后返回新的值,向后一次类推,a的默认值0。
 // ageSum 的值为11

上面两个例子介绍了Stream流最重要的两个使用场景

数据的转换计算

其实Stream流并不复杂,大多数人不会用只是不知道其使用场景。

每个Stream流只能使用一次,一旦终结,如果继续调用的话,会抛出异常,这点一定要注意

Stream常用方法

Stream流中每个方法(除了终结方法)都会返回一个流,当调用终结方法时,整个流才会启动

可以理解为一个工作流水线,最后一步是出产品,在这之前都是对产品加工

下面介绍下加工方法(流水线上的每一步)和终结方法(最终产品的输出)最常用的一些

加工方法(数据加工的方法)

  • map(Function<? super T, ? extends R> mapper)对数据进行转换,相当于一次foreach,然后把每次返回的值作为新流的数据
  • filter(Predicate<? super T> predicate)对数据做过滤,不符合条件的不会加入到后的流中
  • limit(long maxSize)限制流的最大数量,超出部分截断
  • skip(long n)跳过n条数据,和limit配合使用,类似MySql中的limit skip,limit

终结方法(对加工完的数据包装输出)

  • forEach(Consumer<? super T> action)遍历,迭代
  • collect(Collector<? super T, A, R> collector)转换为集合类型或分组处理数据,如:.collect(Collectors.toList())转换为List类型,还有toSet和toMap等
  • reduce(BinaryOperator<T> accumulator)归约操作,每一次调用的结果作为下一次调用的参数,遍历一遍后返回结果

PS:能够掌握上面的方法就能够基本适应大多数场景的要求了

例子

统计每天所有页面的UV(访问的用户数),PV(只要有访问就算一次)

日志数据结构AccessLog

Bash
 // 用户唯一标识
 private Long uid;
 // 页面唯一标识
 private String pageID;
 // 访问日期
 private LocalDate time;

统计结果数据结构Result

Bash
 // UV
 private Long uv;
 // PV
 private Long pv;
 // 页面唯一标识
 private String pageID;
 // 统计日期
 private LocalDate time;

统计过程代码

Bash
 List<AccessLog> logList = new ArrayList<>();
 // ... 数据赋值给logList,省略获取数据的过程
 
 List<Result> resultList = new ArrayList<>();
 // 首先将数据处理成按时间分组的数据
 Map<LocalDate, List<AccessLog>> groupByTime = logList.stream().collect(Collectors.groupingBy(AccessLog::getTime));
 // 遍历每一天的数据
 groupByTime.forEach((localDate, timeList) -> {
     // 再按照页面ID分组,这样就得到了每天每个页面的所有访问日志,接下来就是统计了
     Map<String, List<AccessLog>> groupByPage = timeList.stream().collect(Collectors.groupingBy(AccessLog::getPageID));
     // 在遍历页面分组信息
     groupByPage.forEach((pageId, pageTimeList) -> {
         Result result = new Result();
         result.setPageID(pageId);
         result.setTime(localDate);
         result.setUv(pageTimeList.stream().map(AccessLog::getUid).distinct().count());
         result.setUv((long) pageTimeList.size());
         resultList.add(result);
     });
 });
 // 输出统计结果
 resultList.forEach(System.out::println);

小伙伴们可以想一下,如果不用Stream实现这个需求,要写多少代码才可以完成ヾ(≧▽≦*)o

最后

常用的方法介绍到这里,以后也会继续更新,最重要的是能在平时开发中使用的上,真正提升开发体验的知识;当然也会分享一下自己平时常用的工具和coding技巧给大家,也欢迎评论指出问题和或者提出建议,我都会尽量回答和听取大家建议。

PS:第一次写技术类分享文章,希望大家理性看待,不要暴躁....

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接