Java Stream 使用手册
【摘要】 Java Stream 使用手册在工作中时常会使用 Java Stream 对集合进行特殊操作,Stream 虽然能简化代码,但是书写以及阅读性不高。故在此记录常用的 Stream 案例以便在未来工作中查阅和使用(复制粘贴😅) 一、Stream 介绍Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用...
Java Stream 使用手册
在工作中时常会使用 Java Stream 对集合进行特殊操作,Stream 虽然能简化代码,但是书写以及阅读性不高。故在此记录常用的 Stream 案例以便在未来工作中查阅和使用(复制粘贴😅)
一、Stream 介绍
Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。
使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
1.1 Stream 操作流程
- 创建 Stream:一个数据源(如:集合、数组),获取一个流。
- 中间操作:一个中间操作链,对数据源的数据进行处理。
- 终止操作:一个终止操作,执行中间操作链,并产生结果。
1.2 Stream 的创建
通过 Collection 集合创建
// 获取顺序流
Stream<String> stream = list.stream();
// 获取并行流
Stream<String> parallelStream = list.parallelStream();
复制
通过 Arrays 创建
String[] arr = {"hello","world","abc"};
Stream<String> stream = Arrays.stream(arr);
复制
通过 Stream 的静态方法创建
Stream<String> stream1 = Stream.of("hello","world","abc");
// 获取无限流,迭代
Stream<Integer> stream2 = Stream.iterate(0,(x) -> x + 2);
// 获取无限流,生成
Stream<Integer> stream3 = Stream.generate(() -> (int)(Math.random()));
复制
1.3 Stream 的中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理,而在终止操作时一次性全部处理,称为 “惰性求值”。
筛选与切片
方法 | 说明 |
---|---|
filter(Predicate p) | 接收 Lambda , 从流中过滤出元素 |
distinct() | 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素 |
limit(long maxSize) | 截断流,使其元素不超过给定数量。 |
skip(long n) | 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补 |
@Test
public void test() {
List<Person> list = Arrays.asList(
new Person(1,"aaa",21),
new Person(2,"bbb",22),
new Person(3,"ccc",23),
new Person(4,"ddd",24),
new Person(5,"eee",25)
);
// 中间操作
Stream<Person> stream = list.stream()
.filter((p) -> p.getAge() > 22) // 过滤得到 id 为 3、4、5 的元素
.skip(1) // 跳过 1 个元素,得到 id 为 4、5 元素
.limit(1); // 指获取 1 个元素,得到 id 为 4 的元素
// 终止操作
stream.forEach(System.out::println);
}
复制
映射
方法 | 说明 |
---|---|
map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。 |
mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。 |
mapToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。 |
mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。 |
flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 |
@Test
public void test() {
List<String> list = Arrays.asList("aaa","bbb","ccc");
// 中间操作
Stream<String> stream = list.stream()
.map((str) -> str.toUpperCase()); // 将流中所有元素进行转大写操作
// 终止操作
stream.forEach(System.out::println);
}
复制
排序
方法 | 说明 |
---|---|
sorted() | 产生一个新流,其中按自然顺序排序 |
sorted(Comparator comp) | 产生一个新流,其中按比较器顺序排序 |
@Test
public void test() {
List<String> list = Arrays.asList("ccc","aaa","bbb");
// 中间操作
Stream<String> stream = list.stream().sorted(); // 自然排序
// 终止操作
stream.forEach(System.out::println);
}
复制
1.4 Stream 的终止操作
终止操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是 void 。
查找与匹配
方法 | 说明 |
---|---|
allMatch(Predicate p) | 检查是否匹配所有元素。 |
anyMatch(Predicate p) | 检查是否至少匹配一个元素。 |
noneMatch(Predicate p) | 检查是否没有匹配所有元素。 |
findFirst() | 返回第一个元素。 |
findAny() | 返回当前流中的任意元素。 |
count() | 返回流中元素总数。 |
max(Comparator c) | 返回流中最大值。 |
min(Comparator c) | 返回流中最小值。 |
forEach(Consumer c) | 内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了)。 |
@Test
public void test() {
List<Person> list = Arrays.asList(
new Person(1,"aaa",21),
new Person(2,"bbb",22),
new Person(3,"ccc",23),
new Person(4,"ddd",24),
new Person(5,"eee",25)
);
boolean result = list.stream()
.allMatch((p) -> p.getAge() > 22); // 是否所有元素中年龄大于 22
System.out.println(result);
Optional<Integer> op = list.stream()
.map(Person::getAge) // 获取所有元素的年龄
.max(Integer::compare); // 获取最大年龄
System.out.println(op.get());
}
复制
归约
方法 | 说明 |
---|---|
reduce(T iden, BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值,返回 T。 |
reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值,返回 Optional。 |
@Test
public void test() {
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer result = list.stream().reduce(0, (x,y) -> x + y); // 所有元素进行累加
System.out.println(result);
}
复制
收集
方法 | 说明 |
---|---|
collect(Collector c) | 将流转换为其他形式。接收一个 Collector接口的实现,用于给 Stream 中元素做汇总的方法。 |
@Test
public void test() {
List<Person> list = Arrays.asList(
new Person(1,"aaa",21),
new Person(2,"bbb",22),
new Person(3,"ccc",23),
new Person(4,"ddd",24),
new Person(5,"eee",25)
);
List<String> result = list.stream()
.map(Person::getName) // 获取所有元素的名字
.collect(Collectors.toList()); // 将名字从流中放到新的集合中
System.out.println(result);
}
复制
二、案例汇总
准备测试数据
List<User> userList = new ArrayList<>();
// id: id,name: 姓名,age: 年龄
User user1 = new User(1, "张三", 26);
User user2 = new User(2, "张三", 28);
User user3 = new User(3, "李四", 24);
User user4 = new User(4, "王五", 30);
User user5 = new User(4, "王五2", 31);
userList.add(user1);
userList.add(user2);
userList.add(user3);
userList.add(user4);
userList.add(user5);
复制
2.1 获取 id 集合
List<Integer> idList = userList.stream().map(User::getId).collect(Collectors.toList());
System.out.println("idList:" + idList);
复制
结果:
idList:[1, 2, 3, 4, 4]
复制
2.2 拼接所有用户姓名
String names = userList.stream().map(User::getName).collect(Collectors.joining(","));
System.out.println("names:" + names);
复制
结果:
names:张三,张三,李四,王五,王五2
复制
2.3 年龄递增排序
List<User> sortList = userList.stream().sorted(Comparator.comparing(User::getAge)).collect(Collectors.toList());
System.out.println("sortList:" + sortList);
复制
结果:
sortList:[User [id=3, name=李四, age=24], User [id=1, name=张三, age=26], User [id=2, name=张三, age=28], User [id=4, name=王五, age=30], User [id=4, name=王五2, age=31]]
复制
如要递减,编写 Comparator.comparing(User::getAge).reversed()
。
2.4 过滤出年龄大于 30 的用户
List<User> filterList = userList.stream().filter(i -> i.getAge() > 30).collect(Collectors.toList());
System.out.println("filterList:" + filterList);
复制
结果:
filterList:[User [id=4, name=王五2, age=31]]
复制
2.5 统计年龄小于 30 的用户数量
long count = userList.stream().filter(i -> i.getAge() < 30).count();
System.out.println("count:" + count);
复制
结果:
count:3
复制
2.6 获取年龄最大用户
User maxUser = userList.stream().max(Comparator.comparing(User::getAge)).get();
System.out.println("maxUser:" + maxUser);
复制
结果:
maxUser:User [id=4, name=王五2, age=31]
复制
2.7 获取所有用户年龄总和
Integer totalAge = userList.stream().collect(Collectors.summingInt(User::getAge));
System.out.println("totalAge:" + totalAge);
复制
结果:
totalAge:139
复制
2.8 获取所有用户年龄平均值
Double averageAge = userList.stream().collect(Collectors.averagingDouble(User::getAge));
System.out.println("averageAge:" + averageAge);
复制
结果:
averageAge:27.8
复制
2.9 包含集合总数,年龄最大值, 年龄总和, 年龄平均值
DoubleSummaryStatistics statistics = userList.stream().collect(Collectors.summarizingDouble(User::getAge));
System.out.println("count:" + statistics.getCount() + ", max:" + statistics.getMax() + ", sum:" + statistics.getSum() + ", average:" + statistics.getAverage());
复制
结果:
count:5, max:31.0, sum:139.0, average:27.8
复制
2.10 List 转成 Map
Map<Integer, User> userMap = userList.stream()
.collect(Collectors.toMap(User::getId, Function.identity(), (v1, v2) -> v2));
System.out.println("userMap:" + userMap);
复制
结果:
userMap:{1=User [id=1, name=张三, age=26], 2=User [id=2, name=张三, age=28], 3=User [id=3, name=李四, age=24], 4=User [id=4, name=王五2, age=31]}
复制
其中 (v1, v2) -> v2) 表示 v1,v2 相同时 取 v2
2.11 获取名字对应的的 id 集合
同样是 List 转成 Map 。
Map<String, List<Integer>> userMap = userList.stream()
.collect(Collectors.groupingBy(
User::getName,
Collectors.mapping(User::getId, Collectors.toList()))
);
System.out.println("userMap:" + userMap);
复制
结果:
userMap:{李四=[3], 王五2=[4], 张三=[1, 2], 王五=[4]}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)