title: Java 8 Streams author: Gamehu tags: - Java - '' categories: - 工作 date: 2020-03-22 12:20:00 --- {% asset_img computer-keyboard-34153.jpg Photo by Negative Space from Pexels %} 最近两周被平台组指名道姓拉去当了两周的苦力,写业务层代码,因为逻辑比较复杂数据输入比较多样,所以导致使用集合的概率很高,且常常伴随着过滤、排序等操作,继而用到了很多Streams提供的方法,遂做个简单记录。 ### Streams [官方的解释]: https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html Stream是Java 8中引入的新的抽象层,它提供了一些类似SQL语句的声明性方式处理数据。 流操作分为中间操作和最终操作,元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。 流管道由一个源(例如Collection,数组,生成器函数或I / O通道)组成; 随后是零个或多个中间操作,例如Stream.filter或Stream.map; 以及诸如Stream.forEach或Stream.reduce之类的终端操作。 {% asset_img java-streams.png %} 即将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道中插入节点上进行处理, 比如筛选, 排序,聚合等。 当然为什么喜欢用它还是因为Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。会让代码看起来更加简洁当然通常也会更加高效。 ### API {% asset_img apis.png api %} 如上图api很多,其中又可以按照最开始说的分为中间操作、最终操作两类,中间(**Intermediate**)操作是可以零个或者多个但是最终(**Terminal**)操作只能有一个,能力有限我就列举一下我常用的。 **可能我们需要注意的一个概念**:因为一个 Stream 可以进行多次中间操作,那是不是就会对 Stream 的每个元素进行转换多次,即时间复杂度就是 N(转换次数)个 ?其实不是这样的,转换操作都是 lazy 的,多个转换操作只会在 Terminal 操作的时候融合起来,一次循环完成。 #### 中间操作(intermediate operation) | API | 说明 | | -------- | ---------------------------------------------------------- | | filter | 用于按指定条件过滤元素 | | map | map方法将每个元素映射到其相应的结果,通常用于list转换为map | | limit | limit返回流中的前N个元素,同SQL的limit | | sorted | 对Stream中的元素进行排序 | | distinct | 删除重复项 | #### 最终操作(terminal operation) | API | 说明 | | -------- | ------------------------------------------------------------ | | forEach | 迭代Stream中的元素 | | sum | 对Stream中的元素求和 | | collect | 可以接受各种参数并将流元素累加成集合 | | reduce | 这个方法的主要作用是把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。其实sum等这类也可以说是reduce。 | | max | 获取Stream中符合条件的最大值 | | findAny | 这是一个 termimal 操作,它总是返回 Stream 的符合条件的元素,或者空。注意它的返回值类型是Optional(为了避免空指针)。 | | anyMatch | Stream 中只要有一个元素符合传入的 条件。 | ### 示例 列出几个工作中实践的例子 ``` // 用于按指定条件过滤元素并且把符合条件的添加到指定的集合 List sorted = new ArrayList<>(cis.size()); cis.stream().filter(it -> it.getType() == StrategyType.GLOBAL).forEach(sorted::add); ``` ``` // 拿输入的id到stream中比较是否存在,如果不存在则返回null final List agentEnableIds = getEnableAgenIdsByApp(query.getAppId()); String enableId = agentEnableIds.stream() .filter(id -> agentId.equals(id)) .findAny() .orElse(null); //未开启xx if (isNullOrEmpty(enableId)) { return Collections.emptyList(); } ``` ``` // 两个集合中,集合B中找到符合集合A中的数据,最终得到符合条件的元素集合 agentCmsList.stream().filter(ag -> agentEnableIds.contains(ag.getId())).collect(Collectors.toList()); ``` ``` // checkList的元素作为IpV4Ranges中toRange方法的参数,最终把toRange返回值转换为集合 List checkList = splitter.splitToList(scopesToCheck); List rangesToCheck = checkList.stream().map(IpV4Ranges::toRange).collect(toList()); // failed集合中,去重后的类型失败的有哪些 List types = failed.stream().map(Quality.Metric::getType).distinct().collect(toList()); ``` ``` // Alarm的list集合,转换为map,key为Alarm的appId,value为Alarm List dealingAlarms = dealingAlarmPage.getList(); Map dealingAlarmMap = dealingAlarms.stream().collect(Collectors. toMap(Alarm::getAppId, Function.identity())); ``` ``` // 根据状态排序,如果状态一样按照名称排序 public IBoardAppDataList sortByAppStatus(String[] statusOrder) { return new BoardAppDataList(this.stream().sorted(new Comparator() { private int findStatus(String[] a, BoardAppData target) { return IntStream.range(0, a.length) .filter(i -> String.valueOf(target.getStatus()).equals(a[i])) .findFirst() .orElse(-1); // return -1 if target is not found } @Override public int compare(BoardAppData o1, BoardAppData o2) { int c = findStatus(statusOrder, o1) - findStatus(statusOrder, o2); if (c == 0) { return o1.getAppName().compareTo(o2.getAppName()); } else { return c; } } }).collect(Collectors.toList())); } ``` ``` // 判断输入参数里是否存在任意一个满足haveXssCondition Set keys = paramsObj.keySet(); return keys.stream().anyMatch(key -> haveXssCondition(uri, paramsObj, key)); ``` ### 最后 很显然我这篇仅仅是一个简单的记录文档,如果需要深入了解,还是系统的看相关的文档和源码。而且我主要用的是stream其实还有parallelStream,有兴趣的大家可以看看。 #### 感谢: {% blockquote 陈 争云, 占 宇剑, 和 司 磊 https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/index.html Java 8 中的 Streams API 详解 %} {% endblockquote %}