6、Stream
1、介绍
目的:用于简化集合和数组操作的 API,结合了 Lambda 表达式
Stream 流思想的核心
- 先得到集合或者数组的 Stream 流(就是一根传送带)
- 把元素放上去
- 然后就用这个 Stream 流简化的 API 来方便的操作元素
List<String> names = new ArrayList<>();
Collections.addAll(names, "张无忌", "周芷若", "赵敏", "张强", "张三丰");
names.stream()
.filter(name -> name.startsWith("张"))
.filter(name -> name.length() == 3)
.forEach(System.out::println);
Stream 流的三类方法
- 获取 Stream 流:创建一条流水线,并把数据放到流水线上准备进行操作
- 中间方法:流水线上的操作,一次操作完毕之后,还可以继续进行其他操作
- 终结方法:一个 Stream 流只能有一个终结方法,是流水线上的最后一个操作
2、获取 Stream 流
Stream 操作集合或者数组的第一步是先得到 Stream 流,然后才能使用流的功能
集合获取 Stream 流的方式:可以使用 Collection 接口中的默认方法 stream() 生成流
方法名 | 说明 |
---|---|
default Stream<E> stream() | 获取当前集合对象的 Stream 流 |
Map<String, Integer> map = new HashMap<>();
Set<String> keySet = map.keySet();
Stream<String> keyStream = keySet.stream();
Collection<Integer> values = map.values();
Stream<Integer> valuesStream = values.stream();
Set<Map.Entry<String, Integer>> entries = map.entrySet();
Stream<Map.Entry<String, Integer>> entryStream = entries.stream();
数组获取 Stream 流的方式
方法名 | 说明 |
---|---|
public static <T> Stream<T> stream(T[] array) | 获取当前数组的 Stream 流(Arrays 的 API) |
public static <T> Stream<T> of(T... values) | 获取当前数组 / 可变数据的 Stream 流(Stream 的 API) |
String[] names = {"张三", "李四", "王五"};
Stream<String> stringStream = Arrays.stream(names);
Stream<String> nameStream = Stream.of(names);
3、中间方法
中间方法也称为非终结方法,调用完成后返回新的 Stream 流可以继续使用,支持链式编程
在 Stream 流中无法直接修改集合、数组中的数据
名称 | 说明 |
---|---|
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) | 合并 a 和 b 两个流为一个流 |
Stream<T> filter(Predicate<? super T> predicate) | 用于对流中的数据进行过滤 |
<R> Stream<R> map(Function<? super T, ? extends R> mapper) | 对流中的每个元素进行加工(Function<元素类型, 加工后的类型>) |
Stream<T> limit(long maxSize) | 获取前几个元素 |
Stream<T> skip(long n) | 跳过前几个元素 |
Stream<T> distinct() | 去除流中重复的元素,依赖 hashCode 和 equals 方法 |
Stream<T> sorted(Comparator<? super T> comparator) | 根据比较器规则对流中元素进行排序 |
names.stream().map(new Function<String, String>() {
@Override
public String apply(String name) {
return "亲爱的".concat(name);
}
}).forEach(System.out::println);
注意:中间方法会返回新的流,原来的流就不能用了,流只能使用一次
Stream<String> stringStream = names.stream();
stringStream.filter(name -> name.startsWith("张")); // 会返回新的流, 但是这里并没有接收新的流对象
stringStream.forEach(System.out::println); // 原来的流已经不能用了, 这里会报错
// IllegalStateException: stream has already been operated upon or closed
public class Map_FlatMap {
List<String[]> eggs = new ArrayList<>();
@Before
public void init() {
// 第一箱鸡蛋
eggs.add(new String[]{"鸡蛋_1", "鸡蛋_1", "鸡蛋_1", "鸡蛋_1", "鸡蛋_1"});
// 第二箱鸡蛋
eggs.add(new String[]{"鸡蛋_2", "鸡蛋_2", "鸡蛋_2", "鸡蛋_2", "鸡蛋_2"});
}
// 自增生成组编号
static int group = 1;
// 自增生成学生编号
static int student = 1;
/**
* 把二箱鸡蛋分别加工成煎蛋,还是放在原来的两箱,分给2组学生
*/
@Test
public void map() {
eggs.stream()
.map(x -> Arrays.stream(x).map(y -> y.replace("鸡", "煎")))
.forEach(x -> System.out.println("组" + group++ + ":" + Arrays.toString(x.toArray())));
/*
控制台打印:------------
组1:[煎蛋_1, 煎蛋_1, 煎蛋_1, 煎蛋_1, 煎蛋_1]
组2:[煎蛋_2, 煎蛋_2, 煎蛋_2, 煎蛋_2, 煎蛋_2]
*/
}
/**
* 把二箱鸡蛋分别加工成煎蛋,然后放到一起【10个煎蛋】,分给10个学生
*/
@Test
public void flatMap() {
eggs.stream()
.flatMap(x -> Arrays.stream(x).map(y -> y.replace("鸡", "煎")))
.forEach(x -> System.out.println("学生" + student++ + ":" + x));
/*
控制台打印:------------
学生1:煎蛋_1
学生2:煎蛋_1
学生3:煎蛋_1
学生4:煎蛋_1
学生5:煎蛋_1
学生6:煎蛋_2
学生7:煎蛋_2
学生8:煎蛋_2
学生9:煎蛋_2
学生10:煎蛋_2
*/
}
}
4、终结方法
终结操作方法,调用完成后流就无法继续使用了,原因是不会返回 Stream 了
名称 | 说明 |
---|---|
void forEach(Consumer<? super T> action) | 对此流的每个元素执行遍历操作 |
long count() | 返回此流中的元素数 |
Optional<T> max(Comparator<? super T> comparator) | 根据比较器规则获取流中元素的最大值 |
public T get() | 获取元素(Optional 的 API) |
5、收集 Stream 流
就是把 Stream 流操作后的结果数据恢复到集合或者数组中去
Stream 流:方便操作集合 / 数组的手段
集合 / 数组:才是开发中的目的
名称 | 说明 |
---|---|
R collect(Collector collector) | 开始收集 Stream 流,指定收集器(集合) |
Object[] toArray() | 开始收集 Stream 流,结果为 Object 数组 |
<A> A[] toArray(IntFunction<A[]> generator) | 开始收集 Stream 流,结果为指定类型数组 |
Collectors 工具类提供了具体的收集方式
方法名 | 说明 |
---|---|
public static <T> Collector toList() | 把元素收集到 List 集合中 |
public static <T> Collector toSet() | 把元素收集到 Set 集合中 |
public static Collector toMap(Function keyMapper, Function valueMapper) | 把元素收集到 Map 集合中 |
Object[] objects = names.stream().toArray(); // Object 数组
String[] strings = names.stream().toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int length) {
return new String[length];
}
});
//String[] strings = names.stream().toArray(String[]::new); 指定类型数组
List<String> result = names.stream().filter(name -> name.length() == 3).collect(Collectors.toList()); // 把元素收集到 List 集合中
System.out.println(result);
// 把元素收集到 Map 集合中
List<UserInfo> userInfoList = userService.batchGetUserInfoByUserIds(userIdList);
Map<Long, UserInfo> userInfoMap = userInfoList.stream().collect(Collectors.toMap(UserInfo::getUserId, userInfo -> userInfo));
6、加工演示
// 需求: 把 names 列表转为 Student 数组
public class Student {
private String name;
}
List<String> names = new ArrayList<>();
Collections.addAll(names, "张无忌", "周芷若", "赵敏", "张强", "张三丰");
// 方式一
names.stream().map(new Function<String, Student>() {
@Override
public Student apply(String name) {
return new Student(name);
}
}).forEach(student -> students.add(student));
// names.stream().map(name -> new Student(name)).forEach(student -> students.add(student));
// names.stream().map(Student::new).forEach(students::add);
// 方式二
List<Student> studentList = names.stream().map(Student::new).collect(Collectors.toList());
System.out.println(studentList);
本文来自博客园,作者:lidongdongdong~,转载请注明原文链接:https://www.cnblogs.com/lidong422339/p/17475046.html