谈谈集合.Stream Api(谈谈集合框架)

网友投稿 251 2022-06-07


### 1. 什么是stream API Java8提供的stream API可以让程序员像操作数据库一样操作集合。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。**通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。**常用的stream API有如下; ``` +--------------------+ +------+ +------+ +---+ +-------+ | stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect| +--------------------+ +------+ +------+ +---+ +-------+ ``` **简而言之,Stream API是一个非常高效的数据处理框架。** ### 2. stream的几个特点 - 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。 - 数据源的来源。 可以是集合,数组,I/O channel, 产生器generator 和IntStream等 - 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。 ### 3. Stream API使用列子 #### 3.1 Stream分类 可以从不同的数据源创建stream。java collection包中的Collections,Lists,Sets这些类中新增stream()和parallelStream()方法,通过这些方法可以创建一个顺序stream(sequential streams)或者一个并发的stream(Parallel streams)。并发stream(Parallel streams)更适合在多线程中使用,本文先介绍顺序流(sequential streams)在结尾会描述并发stream(Parallel streams), ``` Arrays.asList("a1", "a2", "a3") .stream() .findFirst() .ifPresent(System.out::println); // a1 1234 ``` List对象上调用stream()方法可以返回一个常规的对象流。在下面的例子中我们不需要创建一个collection对象也可以使用stream: ``` Stream.of("a1", "a2", "a3") .findFirst() .ifPresent(System.out::println); // a1 123 ``` 直接使用Stream.of()方法就能从一组对象创建一个stream对象, 除了常规的对象流,JAVA 8中的IntStream,LongStream,DoubleStream这些流能够处理基本数据类型如:int,long,double。比如:IntStream可以使用range()方法能够替换掉传统的for循环 ``` IntStream.range(1, 4) .forEach(System.out::println); 12 ``` 基本类型流(primitive streams)使用方式与常规对象流类型(regular object streams)大部分相同,但是基本类型流(primitive streams)能使用一些特殊的lambda表达式,比如:用IntFunction代替Function,用IntPredicate代替Predicate,同时`基本类型流(primitive streams)中可以支持一些聚合方法`,如:sum(),average()等。 ``` Arrays.stream(new int[] {1, 2, 3}) .map(n -> 2 * n + 1) .average() .ifPresent(System.out::println); // 5.0 1234 ``` 可以通过常规对象流(regular object stream)的mapToInt(), mapToLong(),mapToDouble(),基本类型对象流(primitive streams)中的mapToObj()等方法完成常规对象流和基本类型流之间的`相互转换` ``` IntStream.range(1, 4) .mapToObj(i -> "a" + i) .forEach(System.out::println); 123 ``` 下面这个例子中doubles stream先被映射成int stream,然后又被映射成String类型的对象流: ``` Stream.of(1.0, 2.0, 3.0) .mapToInt(Double::intValue) .mapToObj(i -> "a" + i) .forEach(System.out::println); // a1 // a2 // a ``` #### 3.2 Stream API的处理顺序 我们用下面的一个列子来引入Stream的处理顺序: ``` Stream.of("d2", "a2", "b1", "b3", "c") .filter(s -> { System.out.println("filter: " + s); return true; }); ``` 想象中,上面的列子会输出下面的内容: ``` filter: d2 filter: a2 filter: b1 filter: b3 filter: c ``` 但是当我们执行这段代码的时候,控制台没有输出任何内容。下面会来讲下出现这个现象的原因。在讲这个原因之前我们先来引入两个Stream相关的概念,能帮助我们更好的理解Stream API: **中间操作和最终操作** > stream包含`中间(intermediate operations)`和`最终(terminal operation)`两种形式的操作。`中间操作(intermediate operations)的返回值还是一个stream`,因此可以通过链式调用将中间操作(intermediate operations)串联起来。`最终操作(terminal operation)只能返回void或者一个非stream的结果。`在上述例子中:filter, map ,sorted是中间操作,而forEach是一个最终操作。更多关于stream的中可用的操作可以查看java doc。上面例子中的链式调用也被称为操作管道流。 > > 大多stream操作接受某种形式的lambda表达式作为参数,通过方法接口的形式指定操作的具体行为,这些方法接口的行为基本上都是无干扰(non-interfering)和无状态(stateless)。无干扰(non-interfering)的方法的定义是:该方法不修改stream的底层数据源,比如上述例子中:没有lambda表达式添加或者删除myList中的元素。无状态(stateless)方法的定义:操作的执行是独立的,比如上述例子中,没有lambda表达式在执行中依赖可能发生变化的外部变量或状态。 **简单粗浅的总结下上面那段话:返回值是还是Stream类型的操作是中间操作,返回值是void或者是非Stream类型的操作的最终操作。Stream的API不会改变原始数据。** 下面是Stream的接口,我们通过返回值就可以清楚的判断哪些是中间操作哪些是最终操作。像我们平时常用的操作filter、map、distinct、sort和limit等都是中间操作。 ``` public interface Stream

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:手把手教你用Abp vnext构建API接口服务(手把手教你用QQ群视频做教研)
下一篇:【asp.net core】实现动态 Web API(aspnet是什么)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~