JDK8 Stream
文章目录
- JDK8 Stream
-
- 概念
- 特点
- 示例
- 流程
- 常用操作符
- 具体用法
-
- 一、流的创建
- 二、Stream中间操作
- 三、Stream最终操作
-
- 1.forEach():遍历流中的每一个元素,执行顺序不一定按照流的顺序。
- 2.forEachOrdered():遍历流中的每一个元素,执行顺序按照流的顺序。
- 3.toArray():将流中的元素放入到一个数组中。
- 4.reduce():这个方法的主要作用是把 Stream 元素组合起来。它提供一个起始值,然后依照运算规则拼接或者运算。
- 5.collect():是Stream的一个函数,负责收集流,将流中的结果汇总。结果是由传入collect()中的Collector定义的。
- 6.min():返回流中的最小值。
- 7.max():返回流中的最大值。
- 8.count():返回流中元素的数量。
- 9.anyMatch():流中只要有一个元素符合传入的断言,就返回 true,否则返回false,如果流为空,永远返回false。
- 10.allMatch():流中所有元素都符合传入的断言时返回 true,否则返回false,流为空时总是返回true。
- 11.noneMatch():流中所有元素都不满足传入的断言时返回 true,否则返回false,流为空时总是返回true。
- 12.findFirst():返回Optional[流中第一个元素],使用`Optional对象.get()`可以获取流中第一个元素。若流为空则返回Optional.empty,使用`Optional对象.get()`会报NoSuchElementException异常。
- 13.findAny():返回Optional[流中的任意一个元素],若流为空则返回Optional.empty。
概念
Stream是JDK8 API的新成员,他允许以声明的方式处理数据集合。
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
特点
代码简洁
函数式编程写出的代码简介且意图明确,使用Stream接口让你从此告别for循环。
多核友好
Java函数式编程使得编写并行程序从未如此简单,你需要的全部就是调用一下方法。
示例
用给出的妹子数据源,按所在地分组,算出妹子的平均薪资
foreach方式
@Test
public void test1() {
List<Girl> girlList = new ArrayList<>();
girlList.add(new Girl("小红", 19, 176, "北京", 7500.0));
girlList.add(new Girl("小玲", 18, 165, "北京", 7000.0));
girlList.add(new Girl("小冬", 22, 173, "湖南", 6000.0));
girlList.add(new Girl("小星", 18, 172, "广西", 4500.0));
girlList.add(new Girl("小莹", 19, 166, "广东", 5300.0));
girlList.add(new Girl("小北", 20, 169, "广东", 6800.0));
/**
* 按所在地分组,算出妹子的平均薪资
*/
/**
* 按所在地分组后的 map:
* {
* 广东 = [Girl {
* name = '小莹', age = 19, height = 166, origin = '广东', salary = 5300.0
* }, Girl {
* name = '小北', age = 20, height = 169, origin = '广东', salary = 6800.0
* }],
* 广西 = [Girl {
* name = '小星', age = 18, height = 172, origin = '广西', salary = 4500.0
* }],
* 湖南 = [Girl {
* name = '小冬', age = 22, height = 173, origin = '湖南', salary = 6000.0
* }],
* 北京 = [Girl {
* name = '小红', age = 19, height = 176, origin = '北京', salary = 7500.0
* }, Girl {
* name = '小玲', age = 18, height = 165, origin = '北京', salary = 7000.0
* }]
* }
*/
//1.基于所在地分组
Map<String, List<Girl>> map = new HashMap<>();
for (Girl girl : girlList) {
List<Girl> list = map.computeIfAbsent(girl.getOrigin(), key -> new ArrayList<>());
list.add(girl);
}
//2.求出不同地方妹子的平均薪资
for (Map.Entry<String, List<Girl>> entry : map.entrySet()) {
Double sum = 0.0;
for (Girl girl : entry.getValue()) {
sum+=girl.getSalary();
}
System.out.println(entry.getKey()+"女孩的平均薪资是"+(sum/entry.getValue().size()));
}
}
运行结果:
广东女孩的平均薪资是6050.0
广西女孩的平均薪资是4500.0
湖南女孩的平均薪资是6000.0
北京女孩的平均薪资是7250.0
Process finished with exit code 0
Stream方式
@Test
public void test2() {
List<Girl> girlList = new ArrayList<>();
girlList.add(new Girl("小红", 19, 176, "北京", 7500.0));
girlList.add(new Girl("小玲", 18, 165, "北京", 7000.0));
girlList.add(new Girl("小冬", 22, 173, "湖南", 6000.0));
girlList.add(new Girl("小星", 18, 172, "广西", 4500.0));
girlList.add(new Girl("小莹", 19, 166, "广东", 5300.0));
girlList.add(new Girl("小北", 20, 169, "广东", 6800.0));
/**
* 按生源地分组,算出妹子的平均薪资
*/
girlList.stream().collect(Collectors.groupingBy(girl -> girl.getOrigin(), //1.基于所在地分组
Collectors.averagingDouble(girl -> girl.getSalary()))) //2.求出不同地方妹子的平均薪资
.forEach((k,v)-> System.out.println(k+"女孩的平均薪资是"+v));
}
运行结果:
广东女孩的平均薪资是6050.0
广西女孩的平均薪资是4500.0
湖南女孩的平均薪资是6000.0
北京女孩的平均薪资是7250.0
Process finished with exit code 0
流程
第一步:把数据源转换为Stream对象
第二步:操作Stream流对象
Stream流对象在管道中经过中间操作的处理,最终操作得到前面处理的结果。
操作特性
- Stream不存储数据:Stream不是一种数据结构,它只是某种数据源的一个视图,数据源可以是一个数组,Java容器或I/O channel等。
- Stream不改变数据源:Stream的任何修改都不会修改背后的数据源,比如对Stream执行过滤操作并不会删除被过滤的元素,而是会产生一个不包含被过滤元素的新Stream。
- Stream不可重复使用:Stream只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成。
常用操作符
方法 | 描述 | 类型 |
---|---|---|
filter() | 该方法用于通过设置的条件过滤出元素。 | 中间操作 |
distinct() | 通过流中元素的 hashCode() 和 equals() 去除重复元素。 | 中间操作 |
limit() | 获取流中的前n个元素。 | 中间操作 |
skip() | 获取流中的除去前n个元素的其他元素。 | 中间操作 |
sorted() | 它使用自然顺序对流的元素进行排序。 | 中间操作 |
peek() | 对每个元素执行操作并返回一个新的Stream。 | 中间操作 |
map() | 对流中的所有元素进行统一操作。 | 中间操作 |
flatmap() | 对流进行扁平化处理。 | 中间操作 |
forEach() | 遍历流中的每一个元素,执行顺序不一定按照流的顺序。 | 最终操作 |
forEachOredered() | 遍历流中的每一个元素,执行顺序按照流的顺序。 | 最终操作 |
toArray() | 将流中的元素放入到一个数组中。 | 最终操作 |
reduce() | 是把流元素组合起来。它提供一个起始值,然后依照运算规则拼接或者运算。 | 最终操作 |
collect() | 负责收集流,将流中的结果汇总。结果是由传入collect()中的Collector定义的。 | 最终操作 |
min() | 返回流中的最小值。 | 最终操作 |
max() | 返回流中的最大值。 | 最终操作 |
count() | 返回流中元素的数量。 | 最终操作 |
anyMatch() | 流中只要有一个元素符合传入的断言,就返回 true,否则返回false,如果流为空,永远返回false。 | 最终操作 |
allMatch() | 流中所有元素都符合传入的断言时返回 true,否则返回false,流为空时总是返回true。 | 最终操作 |
noneMatch() | 流中所有元素都不满足传入的断言时返回 true,否则返回false,流为空时总是返回true。 | 最终操作 |
findFirst() | 返回Optional[流中第一个元素],使用Optional对象.get() 可以获取流中第一个元素。若流为空则返回Optional.empty,使用Optional对象.get() 会报NoSuchElementException异常。 |
最终操作 |
findAny() | 返回Optional[流中的任意一个元素],若流为空则返回Optional.empty。 | 最终操作 |
具体用法
一、流的创建
1.1使用Collection下的 stream() 和 parallelStream() 方法。
@Test
public void create(){
List<String> stringList = Arrays.asList("ad", "", "cbx", "cbx", "", "abf", "ged");
Stream<String> stream = stringList.stream(); //获取一个串行流
Stream<String> parallelStream = stringList.parallelStream(); //获取一个并行流
}
串行流:用于主线程,单线程
并行流:用于多个线程同时运行
1.2 使用Arrays 中的 stream() 方法,将数组转成流。