Java 8 Stream流API解析
1. Stream流简介
Java 8 API添加了一个新的抽象称为流Stream,可以以一种声明的方式处理数据。
Stream流使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
Stream流特点:
- 不是数据结构,不会保存数据,只是在原数据集上定义了一组操作
- 惰性求值,流在中间处理过程中,只是对操作进行了记录,并不会立即执行,需要等到执行终止操作的时候才会进行实际的计算
- Stream不保存数据,它会将操作后的数据保存到另外一个对象中
一般使用步骤:
- 获取数据源,创建流
- 中间操作(Intermediate):可以有多个,每次返回一个新的流,可进行链式操作
- 终端操作(Terminal):只能有一个,每次执行完,这个流也就用光光了,无法执行下一个操作
2. Stream流的创建方式
package com.jbp.controller;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.regex.Pattern;
import java.util.stream.Stream;
/** * @ClassName: StreamAPI * @description: * @author: JiangBeiPing * @create: 2021-06-18 11:07 * @Version: 1.0 **/
public class StreamAPI {
public static void main(String[] args) throws FileNotFoundException {
// 1.Stream创建
// 数组 -----------------------------------------
// 数组:Arrays.stream(T array)
Integer[] array = { 1, 2, 3};
Stream<Integer> integerStream1 = Arrays.stream(array);
// 集合 Collection ------------------------------
List<Integer> list = Arrays.asList(array);
// 集合: Collection.stream()
Stream<Integer> listStream1 = list.stream();
// 集合: Collection.parallelStream() 默认使用的是 ForkJoinPool.commonPool()线程池
Stream<Integer> listStream2 = list.parallelStream();
// BufferedReader -------------------------------
BufferedReader reader = new BufferedReader(new FileReader("xxx"));
Stream<String> linesStream = reader.lines();
// 字符串处理 String ------------------------------
String str = "1,2,3";
Pattern pattern = Pattern.compile(",");
Stream<String> stringStream = pattern.splitAsStream(str);
// Stream自带的静态方法 ----------------------------
// Stream.of()
Stream<Integer> integerStream = Stream.of(1, 2, 3);
// Stream.iterate()
Stream<Integer> integerStream2 = Stream.iterate(1, s -> (s + 2));
// Stream.generate()
Stream<Double> generate = Stream.generate(Math::random);
}
}
3. Stream流API分类
API | 类型 | 返回类型 | 使用的类型/函数式接口 | 函数描述符 |
---|---|---|---|---|
filter | 中间操作(Intermediate) | Stream < T > | Predicate < T > | T - > boolean |
distinct | 中间操作(Intermediate,有状态 - 无界) | Stream < T > | — | — |
skip | 中间操作(Intermediate,有状态 - 有界) | Stream < T > | long | — |
map | 中间操作(Intermediate) | Stream < T > | Function < T,R > | T - > R |
flatMap | 中间操作(Intermediate) | Stream < T > | Function < T,Stream < R > > | T - > Stream < R > |
sorted | 中间操作(Intermediate,有状态 - 无界) | Stream < T > | Compartor < T > | (T,T) - > int |
anyMatch | 终端操作(Terminal) | boolean | Predicate < T > | T - > boolean |
noneMatch | 终端操作(Terminal) | boolean | Predicate < T > | T - > boolean |
allMatch | 终端操作(Terminal) | boolean | Predicate < T > | T - > boolean |
findAny | 终端操作(Terminal) | Optional < T > | — | — |
findFirst | 终端操作(Terminal) | Optional < T > | — | — |
forEach | 终端操作(Terminal) | void | Consumer < T > | T - > void |
collect | 终端操作(Terminal) | R | Collector <T,A,R> | — |
reduce | 终端操作(Terminal,有状态 - 有界) | Optional < T > | BinaryOperator < T > | (T,T) - > T |
count | 终端操作(Terminal) | long | — | — |
- 有状态:指该操作只有拿到所有元素之后才能继续下去
- 无状态:指元素的处理不受之前元素的影响
4. Stream流中间操作API
4.1 filter 过滤
将结果为false的元素过滤掉,为true会把当前元素会保留下来。
数值型过滤:
Integer[] array = { 1, 2, 3};
Stream<Integer> integerStream1 = Arrays.stream(array);
Stream<Integer> filterStream = integerStream1.filter(i -> i == 2);
System.out.println(Arrays.toString(filterStream.toArray())); // [2]
对象型过滤:
User user1 = new User(1,"张三");
User user2 = new User(2,"李四");
User user3 = new User(3,"王五");
ArrayList<User> users = new ArrayList<>();
users.add(user1);
users.add(user2);
users.add(user3);
Stream<User> userStream = users.stream().filter(user -> "王五".equals(user.getName()));
System.out.println(Arrays.toString(userStream.toArray())); // [StreamAPI.User(id=3, name=王五)]
4.2 map 映射
接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
数组类型映射:
Integer[] array = { 1, 2, 3};
Stream<Integer> integerStream1 = Arrays.stream(array);
Stream<Integer> mapStream = integerStream1.map(i -> {
i++;
return i;
});
System.out.println(Arrays.toString(mapStream.toArray())); // [2, 3, 4]
对象类型映射:
User user1 = new User(1,"张三");
User user2 = new User(2,"李四");
User user3 = new User(3,"王五");
ArrayList<User> users = new ArrayList<>();
users.add(user1);
users.add(user2);
users.add(user3);
Stream<User> mapStream2 = users.stream().map(user -> {
String name = user.getName();
user.setName(name + "xx");
return user;
});
System.out.println(Arrays.toString(mapStream2.toArray())); // [StreamAPI.User(id=1, name=张三xx), StreamAPI.User(id=2, name=李四xx), StreamAPI.User(id=3, name=王五xx)]
4.3 flatMap 映射
接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
数组类型映射:
Integer[] array = { 1, 2, 3};
Integer[] array2 = { 8, 9, 10};
Stream<Integer> integerStream1 = Arrays.stream(array);
// 每个元素 i 转换为一次新的stream流 并返回
Stream<Integer> mapStream = integerStream1.flatMap(i -> {
Stream<Integer> stream = Arrays.stream(array2);
return stream;
});
System.out.println(Arrays.toString(mapStream.toArray())); // [8, 9, 10, 8, 9, 10, 8, 9, 10]
对象类型映射:
User user1 = new User(1,"张三");
User user2 = new User(2,"李四");
User user3 = new User(3,"王五");
ArrayList<User> users = new ArrayList<>();
users.add(user1);
users.add(user2);
users.add(user3);
Stream<String> stringStream = users.stream().flatMap(user -> {
String name = user.getName();
String[] split = name.split("");
Stream<String> stream = Arrays.stream(split);
return stream;
});
System.out.println(Arrays.toString(stringStream.toArray())); // [张, 三, 李, 四, 王, 五]
4.4 forEach 遍历
Integer[] array = { 1, 2, 3};
Stream<Integer> integerStream1 = Arrays.stream(array);
// 遍历array数组 ---> 1,2,3
integerStream1.forEach(i -> {
System.out.println(i);
});
4.5 limit 截取
保留前n个元素
Integer[] array = { 1, 2, 3};
Stream<Integer> integerStream1 = Arrays.stream(array);
Stream<Integer> integerStream = integerStream1.limit(2);
System.out.println(Arrays.toString(integerStream.toArray())); // [1, 2]
4.6 skip 跳过
跳过前n个元素
Integer[] array = { 1, 2, 3};
Stream<Integer> integerStream1 = Arrays.stream(array);
Stream<Integer> integerStream = integerStream1.skip(2);
System.out.println(Arrays.toString(integerStream.toArray())); // [3]
4.7 distinct 去重
剔除重复元素
Integer[] array = { 1, 2, 3,3};
Stream<Integer> integerStream1 = Arrays.stream(array);
Stream<Integer> integerStream = integerStream1.distinct();
System.out.println(Arrays.toString(integerStream.toArray())); // [1, 2, 3]
4.8 sorted 排序
- sorted():自然排序,流中元素需实现Comparable接口
sorted(Comparator com):定制排序,自定义Comparator排序器
Integer[] array = { 1, 2, 3,8,5};
StreamintegerStream1 = Arrays.stream(array);
StreamintegerStream = integerStream1.sorted();
System.out.println(Arrays.toString(integerStream.toArray())); // [1, 2, 3, 5, 8]Integer[] array = { 1, 2, 3,8,5};
StreamintegerStream1 = Arrays.stream(array);
// 倒序排列
StreamintegerStream = integerStream1.sorted((i1,i2) -> { return i2 - i1;
});
System.out.println(Arrays.toString(integerStream.toArray())); // [8, 5, 3, 2, 1]
4.9 peek 消费
如同于map,能得到流中的每一个元素。但map接收的是一个Function表达式,有返回值;而peek接收的是Consumer表达式,没有返回值
User user1 = new User(1,"张三");
User user2 = new User(2,"李四");
User user3 = new User(3,"王五");
ArrayList<User> users = new ArrayList<>();
users.add(user1);
users.add(user2);
users.add(user3);
Stream<User> peek = users.stream().peek(user -> {
String name = user.getName();
user.setName(name + "v");
});
System.out.println(Arrays.toString(peek.toArray())); // [StreamAPI.User(id=1, name=张三v), StreamAPI.User(id=2, name=李四v), StreamAPI.User(id=3, name=王五v)]
5. Stream流终止操作API
5.1 匹配、聚合操作
匹配:
- anyMatch(),只要有一个元素匹配传入的条件,就返回 true
- allMatch(),只有有一个元素不匹配传入的条件,就返回 false;如果全部匹配,则返回true
noneMatch(),只要有一个元素匹配传入的条件,就返回 false;如果全部匹配,则返回 true
Integer[] array = { 1, 2, 3,8,5};
StreamintegerStream1 = Arrays.stream(array);
boolean anyMatch = integerStream1.anyMatch(i -> i > 6); // true
System.out.println(anyMatch);
boolean allMatch = integerStream1.allMatch(i -> i > 6); // false
System.out.println(allMatch);
boolean noneMatch = integerStream1.noneMatch(i -> i > 6); // false
System.out.println(noneMatch);
聚合:
- findFirst:返回流中第一个元素
- findAny:返回流中的任意元素
- count:返回流中元素的总个数
- max:返回流中元素最大值
min:返回流中元素最小值
Integer[] array = { 1, 2, 3,8,5};
StreamintegerStream1 = Arrays.stream(array);
Optionalfirst = integerStream1.findFirst();// 1
Optionalany = integerStream1.findAny();
long count = integerStream1.count(); // 5
Optionalmax = integerStream1.max(Integer::compareTo);// Optional[8]
Optionalmin = integerStream1.min(Integer::compareTo);//Optional[1]
5.2 归并
合并流的元素并产生单个值
- Optional reduce(BinaryOperator accumulator)
- T reduce(T identity, BinaryOperator accumulator)
- < U > U reduce(U identity,BiFunction accumulator,BinaryOperator combiner)
identity = 默认值或初始值
BinaryOperator = 函数式接口,取两个值并产生一个新值。(注: java Function 函数中的 BinaryOperator 接口用于执行 lambda 表达式并返回一个 T 类型的返回值)
Integer[] array = { 1, 2, 3,8,5};
int sum = 0;
for (Integer i : array) {
sum += i;
}
System.out.println(sum); // 19
Stream<Integer> integerStream1 = Arrays.stream(array);
Integer reduce = integerStream1.reduce(0, (a, b) -> a + b);
System.out.println(reduce);// 19
6. Stream流收集器collect
集合、聚合收集:
User user1 = new User(1,"张三");
User user2 = new User(2,"李四");
User user3 = new User(3,"王五");
ArrayList<User> users = new ArrayList<>();
users.add(user1);
users.add(user2);
users.add(user3);
// list
List<Integer> list = integerStream1.collect(Collectors.toList());
// set
Set<Integer> set = integerStream1.collect(Collectors.toSet());
// map key不能相同
Map<Integer, String> map = users.stream().collect(Collectors.toMap(User::getId, User::getName));
// 获取users元素个数
Long count = users.stream().collect(Collectors.counting());
// 获取users集合id最大值
Optional<Integer> max = users.stream().map(User::getId).collect(Collectors.maxBy(Integer::compare));
// 获取users集合id最小值
Optional<Integer> min = users.stream().map(User::getId).collect(Collectors.minBy(Integer::compare));
// 获取users集合所有id的和
Integer id = users.stream().collect(Collectors.summingInt(User::getId));
// 获取users集合所有id的平均值
Double average = users.stream().collect(Collectors.averagingDouble(User::getId));
字符串拼接:
String s = users.stream().map(User::getName).collect(Collectors.joining(",", "{", "}"));// {张三,李四,王五}
分组、分区和归并:
User user1 = new User(1,"张三");
User user2 = new User(2,"李四");
User user3 = new User(2,"王五");
ArrayList<User> users = new ArrayList<>();
users.add(user1);
users.add(user2);
users.add(user3);
// 按照id分组
Map<Integer, List<User>> group = users.stream().collect(Collectors.groupingBy(User::getId));// {1=[StreamAPI.User(id=1, name=张三)], 2=[StreamAPI.User(id=2, name=李四), StreamAPI.User(id=2, name=王五)]}
// 多重分组:先按照名字分,再按照id分
Map<String, Map<Integer, List<User>>> map = users.stream().collect(Collectors.groupingBy(User::getName, Collectors.groupingBy(User::getId)));//{李四={2=[StreamAPI.User(id=2, name=李四)]}, 张三={1=[StreamAPI.User(id=1, name=张三)]}, 王五={2=[StreamAPI.User(id=2, name=王五)]}}
// 按照id分区:大于1为一部分,小于等于1为一部分
Map<Boolean, List<User>> collect = users.stream().collect(Collectors.partitioningBy(user -> user.getId() > 1));//{false=[StreamAPI.User(id=1, name=张三)], true=[StreamAPI.User(id=2, name=李四), StreamAPI.User(id=2, name=王五)]}
// 归并:计算users集合的id之和
Optional<Integer> sum = users.stream().map(User::getId).collect(Collectors.reducing(Integer::sum));//Optional[5]
还没有评论,来说两句吧...