Stream API 介绍
Java8中有两个最为重要的改变。第一个是Lambda表达式;另一个就是Stream API 。它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。Stream(流)是一个来自数据源的元素队列并支持聚合操作。元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
需要注意的是:
- Stream 不会存储元素
- Stream 不会改变数据源对象。而是返回一个持有结果的新的Stream
- Stream 操作是延迟执行的。
操作Stream的三个步骤
- 创建Stream:获取数据源的流
- 中间操作:一系列针对数据源数据的操作(操作连)
- 终止操作:执行中间的所有操作,并产生结果
与Collection操作不同, Stream操作还有两个基础的特征:
Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道,
如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式,
显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式,
通过访问者模式(Visitor)实现。
记录代码:
//创建一个数据源 多个stds 对象组成的json数组
String strs="[ { \"stdid\": \"1\", \"score\": \"20\", \"ts\": \"2019-11-15 13:30:10\" }, { \"stdid\": \"2\", \"score\": \"22\", \"ts\": \"2019-11-15 13:31:08\" }, { \"stdid\": \"3\", \"score\": \"20.2\", \"ts\": \"2019-11-14 13:31:20\" }, { \"stdid\": \"4\", \"score\": \"25\", \"ts\": \"2019-11-15 13:33:27\" }, { \"stdid\": \"5\", \"score\": \"20\", \"ts\": \"2019-11-13 13:33:36\" }, { \"stdid\": \"6\", \"score\": \"21.2\", \"ts\": \"2019-11-15 13:33:47\" }, { \"stdid\": \"7\", \"score\": \"26\", \"ts\": \"2019-11-15 13:37:05\" }, { \"stdid\": \"8\", \"score\": \"29\", \"ts\": \"2019-11-15 13:37:31\" }, { \"stdid\": \"9\", \"score\": \"30\", \"ts\": \"2019-11-19 13:37:38\" }, { \"stdid\": \"10\", \"score\": \"12\", \"ts\": \"2019-11-15 13:37:58\" }, { \"stdid\": \"11\", \"score\": \"15\", \"ts\": \"2019-11-22 13:38:04\" }, { \"stdid\": \"12\", \"score\": \"15\", \"ts\": \"2019-11-11 13:38:04\" } ]";
// 通过GSON 解析成List,也可以通过fastjson进行解析成数组
Gson gson=new Gson();
JsonParser parser = new JsonParser();
final JsonElement parse = parser.parse(strs);
final JsonArray asJsonArray = parse.getAsJsonArray(); //解析成json数组
List<Stds> stds=new ArrayList<>();
asJsonArray.forEach(jsonElement -> {
stds.add(gson.fromJson(jsonElement, Stds.class));
});
//数据源整理好之后,下面就是正式的流处理实战了
// (小试牛刀一波)需求: 取 在时间2019-11-15 13:37:31之前的连续5条数据(按时间排序)的分数前三的平均数
//1.先根据时间排序降序(),
final double average = stds.stream().
sorted(Comparator.comparing(Stds::getTs).
reversed()).
filter(stds2 -> stds2.getTs().getTime() < Timestamp.valueOf("2019-11-15 13:37:31").getTime()).
limit(5).
sorted(Comparator.comparing(Stds::getScore).reversed()).
limit(3).
mapToDouble(e -> e.getScore()).summaryStatistics().getAverage();
System.out.println(average);
// collector 处理完流得到的是Stream对象,一般我们会转为集合
final List<Stds> collect = stds.stream().collect(Collectors.toList());
System.out.println(collect.toString());
实体类:
public class Stds {
private Integer stdid;
private Double score;
private Timestamp ts;
}