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)