JAVA8 Stream流

2020-06-02 16:06:37来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

JAVA8 Stream流

简介

Stream 是一个 Collection 的增强工具,可以对集合进行各种操作,而且可以很方便的写出并发程序,学习之前需要了解一些函数,可以看 JAVA8 Lambda表达式。常见的获取方式就是 Collection.stream()

操作类型

操作类型分为三种

  • Intermediate(中间操作):可以多次使用,因为返回一个 Stream。比如 map(mapToInt, flatMap)filtersortedlimitskip
  • Terminal(结束操作):使用后就会结束。比如 forEachsortcollectmincountfindFirstanyMatch

中间操作都是惰性的,也就是延迟的,所以会产生副作用,关于副作用会在之后的章节详细说明。

创建

Stream 的类型有三种 IntStreamDoubleStream LongStream,当然也可以使用 Stream<T>

除了直接创建,还能通过 Collection 接口的 stream()parallelStream() 创建,其中 parallelStream() 创建的流是并发、线程不安全且操作无序的,虽然它是并发的,但仍有可能在某些操作下变回串行的,例如 forEachOrdered,此外还需要保证数据源是线程安全的。

下面的代码展示了流的创建,第二行代码是取流中前三个元素在控制台输出,如果开启最后一行注释将会出现 java.lang.IllegalStateException 的异常,详细错误信息为 stream has already been operated upon or closed,所以创建的 Stream 仅能使用一次。

IntStream intStream = IntStream.of(1, 2, 3, 4);
intStream.limit(3).forEach(System.out::println);
//intStream.limit(1).forEach(System.out::println);

使用

JAVA8 中 Stream 接口中的操作有 filtermapmapToIntmapToLongmapToDoubleflatMapflatMapToIntflatMapToLongflatMapToDoubledistinctsortedpeeklimitskipforEachforEachOrderedtoArrayreducecollectminmaxcountanyMatchallMatchnoneMatchfindFirstfindAny,方法很多,没见过的看注释、参数和返回值就懂了。

示例使用 List 接口 的 stream 方法创建 Stream,下面是示例所需要的数据。

//Get、Set、构造方法浪费空间,不粘贴了
public class Person {
  //id
  private Integer id;
  //名字
  private String name;
  //年龄
  private Integer age;
  //组织
  private String organization;
}
//数据初始化
List<Person> personList = new ArrayList<>();
personList.add(new Person(1, "灰原哀", 7, "帝丹小学"));
personList.add(new Person(2, "江户川柯南", 7, "帝丹小学"));
personList.add(new Person(3, "宫野明美", 24, "黑衣组织"));
personList.add(new Person(4, "赤井秀一", 27, "FBI"));
personList.add(new Person(5, "贝尔摩德", 29, "黑衣组织"));

下面是对 Stream 操作的两个个简单示例。

第一个将 personList 中 前 4 个、年龄为 7 的人提取出来,以组织和姓名为 keyvalue 组装成一个新的 Map,其中 Collectors.toMap 方法最后一个参数用于解决 key 冲突。

第二个获取 personList 中名字为安室透的第一个人。

Map<String, String> map = personList.stream().limit(4) //中间操作
        .filter(person -> Objects.equals(person.getAge(), 7)) //中间操作
        .collect(Collectors.toMap( // Collectors 类是随 Stream 一起引入的,即方便又好看,作用之一是收集元素到集合
                Person::getOrganization, // map 的 key
                Person::getName, // map 的 value
                (old, now) -> old)); // 发生冲突的解决办法
Optional<Person> optional = personList.stream()
        .filter(person->Objects.equals(person.getName(), "安室透")) //中间操作
        .findFirst();

第二个方法返回值类型是 Optional<Person>Optional 是 JAVA8 中引入的一个容器,可以使用 get() 获取容器中的值,但 optional 中并没有值,所以会抛出 java.util.NoSuchElementException,为了解决这个问题可以使用 orElse(),当容器中值为空时返回设定的默认值,除了 orElse 还有 orElseGetorElseThrow。比如下面的这段代码返回了叫安室透的人。

// optional 在上一段代码中产生的对象
Person person = optional.orElse(new Person(7, "安室透", 29, "日本公安"));

副作用

对流的中间操作会产生副作用,结果是抛异常和数据的错误,它的来源有“干扰”和“有状态的 Lambda”。

  • “干扰”就是在中间操作时修改了流的数据源。比如在 forEach(Consumer<? super T> action) 中应该是消费数据,却给数据源添加了一个数据,结果是抛出了 java.util.ConcurrentModificationException 异常。
  • “有状态的 Lambda”,当后面操作产生的结果会被前面的操作影响时,前面操作的 Lambda 就被称作是有状态的。比如 有状态的 Lambda 的例子,例子中使用 parallelStream() 并发添加数据到 parallelStorage 中,结果就是 parallelStorage 中的数据顺序不可预测,因此称 e -> { parallelStorage.add(e); return e; } 是有状态的 Lambda

总结

本文没有深入介绍它的概念,只是简单介绍了 Stream 的使用和 Optional 容器,对于了解应该够了。

参考资料

为什么需要 Stream

Stream 副作用

Java 8 Stream 的终极技巧——Collectors 功能与操作方法详解

Java8(3)Stream类的collect方法详解


原文链接:https://www.cnblogs.com/hligy/p/13033718.html
如有疑问请与原作者联系

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:更新下简历,没想到系统推荐给我的岗位全变成外包了

下一篇:dockerMesos配置项是怎么解析的?案例详解