JDK 1.8 新特性之Stream 详解个人笔记

本文转载自链接:https://blog.csdn.net/chenhao_c_h/article/details/80691284

首先对stream的操作可以分为两类,中间操作(intermediate operations)和结束操作(terminal operations):

  • 中间操作总是会惰式执行,调用中间操作只会生成一个标记了该操作的新stream。
  • 结束操作会触发实际计算,计算发生时会把所有中间操作积攒的操作以pipeline的方式执行,这样可以减少迭代次数。计算完成之后stream就会失效。

虽然大部分情况下stream是容器调用Collection.stream()方法得到的,但stream和collections有以下不同:

  • 无存储。stream不是一种数据结构,它只是某种数据源的一个视图,数据源可以是一个数组,Java容器或I/O channel等。
  • 为函数式编程而生。对stream的任何修改都不会修改背后的数据源,比如对stream执行过滤操作并不会删除被过滤的元素,而是会产生一个不包含被过滤元素的新stream。
  • 惰式执行。stream上的操作并不会立即执行,只有等到用户真正需要结果的时候才会执行。
  • 可消费性。stream只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成。

一、获取stream

// 1、数组
String[] arr = new String[]{"ab", "cd", "ef"};
Stream<String> arrStream = Arrays.stream(arr);
// 2、集合
List<String> list = Arrays.asList("ab", "cd", "ef");
Stream<String> colStream = list.stream();
// 3、值
Stream<String> stream = Stream.of("ab", "cd", "ef");

二、stream方法使用

user类

public class User {
	private String name;
	private int age;

	public User() {
	}

	public User(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		User other = (User) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "User{" + "name='" + name + '\'' + ", age=" + age + '}';
	}
}

测试数据:

List<User> list = Arrays.asList(
	// name,age
	new User("张三", 11), 
	new User("王五", 20), 
	new User("王五", 91), 
	new User("张三", 8), 
	new User("李四", 44), 
	new User("李四", 44), 
	new User("李四", 44)
);

1、forEach() 使用该方法迭代流中的每个数据

// java 8 前
System.out.println("java 8 前");
for (User user : list) {
	System.out.println(user);
}
// java 8 lambda
System.out.println("java 8 lambda");
list.forEach(user -> System.out.println(user));

// java 8 stream lambda
System.out.println("java 8 stream lambda");
list.stream().forEach(user -> System.out.println(user));

java 8 前
User{name=‘张三’, age=11}
User{name=‘王五’, age=20}
User{name=‘王五’, age=91}
User{name=‘张三’, age=8}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
java 8 lambda
User{name=‘张三’, age=11}
User{name=‘王五’, age=20}
User{name=‘王五’, age=91}
User{name=‘张三’, age=8}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
java 8 stream lambda
User{name=‘张三’, age=11}
User{name=‘王五’, age=20}
User{name=‘王五’, age=91}
User{name=‘张三’, age=8}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}

2、sorted() 使用该方法排序数据

System.out.println("-----排序前-----");
list.forEach(user -> System.out.println(user));
System.out.println("-----排序后-----");
// java 8 前
System.out.println("java 8 前");
Collections.sort(list, new Comparator<User>() {
	@Override
	public int compare(User o1, User o2) {
		return Integer.valueOf(o1.getAge()).compareTo(Integer.valueOf(o2.getAge()));
	}
});
for (User user : list) {
	System.out.println(user);
}
// java 8 stream 方法引用
System.out.println("java 8 stream 方法引用");
list.stream().sorted(Comparator.comparing(User::getAge)).forEach(user -> System.out.println(user));

-----排序前-----
User{name=‘张三’, age=11}
User{name=‘王五’, age=20}
User{name=‘王五’, age=91}
User{name=‘张三’, age=8}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
-----排序后-----
java 8 前
User{name=‘张三’, age=8}
User{name=‘张三’, age=11}
User{name=‘王五’, age=20}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
User{name=‘王五’, age=91}
java 8 stream 方法引用
User{name=‘张三’, age=8}
User{name=‘张三’, age=11}
User{name=‘王五’, age=20}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
User{name=‘王五’, age=91}

3、filter():使用该方法过滤

// 输出年龄大于50的人
System.out.println("-----过滤前-----");
list.forEach(user -> System.out.println(user));
System.out.println("-----过滤后-----");
// java 8 前
System.out.println("java 8 前");
for (User user : list) {
	if (user.getAge() > 50) {
		System.out.println(user);
	}
}
// java 8 stream
System.out.println("java 8 stream");
list.stream().filter((User user) -> user.getAge() > 50).forEach(user -> System.out.println(user));

-----过滤前-----
User{name=‘张三’, age=11}
User{name=‘王五’, age=20}
User{name=‘王五’, age=91}
User{name=‘张三’, age=8}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
-----过滤后-----
java 8 前
User{name=‘王五’, age=91}
java 8 stream
User{name=‘王五’, age=91}

4、limit():使用该方法截断

// 从第三个开始截断,只输出前三个
System.out.println("-----截断前-----");
list.forEach(user -> System.out.println(user));
System.out.println("-----截断后-----");
// java 8 前
System.out.println("java 8 前");
for (int i = 0; i < 3; i++) {
	System.out.println(list.get(i));
}
// java 8 stream
System.out.println("java 8 stream");
list.stream().limit(3).forEach(user -> System.out.println(user));

-----截断前-----
User{name=‘张三’, age=11}
User{name=‘王五’, age=20}
User{name=‘王五’, age=91}
User{name=‘张三’, age=8}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
-----截断后-----
java 8 前
User{name=‘张三’, age=11}
User{name=‘王五’, age=20}
User{name=‘王五’, age=91}
java 8 stream
User{name=‘张三’, age=11}
User{name=‘王五’, age=20}
User{name=‘王五’, age=91}

5、skip():与limit互斥,使用该方法跳过元素

// 跳过前三个元素,从第四个开始输出
System.out.println("-----跳过前-----");
list.forEach(user -> System.out.println(user));
System.out.println("-----跳过后-----");
// java 8 前
System.out.println("java 8 前");
for (int i = 3; i < list.size(); i++) {
	System.out.println(list.get(i));
}
// java 8 stream
System.out.println("java 8 stream");
list.stream().skip(3).forEach(user -> System.out.println(user));

-----跳过前-----
User{name=‘张三’, age=11}
User{name=‘王五’, age=20}
User{name=‘王五’, age=91}
User{name=‘张三’, age=8}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
-----跳过后-----
java 8 前
User{name=‘张三’, age=8}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
java 8 stream
User{name=‘张三’, age=8}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}

6、distinct():使用该方法去重,注意:必须重写对应泛型的hashCode()和equals()方法

// 因为Arrays.asList() 返回的是Arrays的内部类ArrayList,操作remove,add会报错
List<User> users = new ArrayList(list);
// 为list去除重复数据
System.out.println("-----去重前-----");
list.forEach(user -> System.out.println(user));
System.out.println("-----去重后-----");
// java 8 前
System.out.println("java 8 前");
for (int i = 0; i < users.size() - 1; i++) {
	for (int j = users.size() - 1; j > i; j--) {
		if (users.get(j).getAge() == users.get(i).getAge()
				&& users.get(j).getName().equals(users.get(i).getName())) {
			users.remove(i);
		}
	}
}
for (User user : users) {
	System.out.println(user);
}
// java 8 stream
System.out.println("java 8 stream");
users.stream().distinct().forEach(user -> System.out.println(user));

-----去重前-----
User{name=‘张三’, age=11}
User{name=‘王五’, age=20}
User{name=‘王五’, age=91}
User{name=‘张三’, age=8}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
-----去重后-----
java 8 前
User{name=‘张三’, age=11}
User{name=‘王五’, age=20}
User{name=‘王五’, age=91}
User{name=‘张三’, age=8}
User{name=‘李四’, age=44}
java 8 stream
User{name=‘张三’, age=11}
User{name=‘王五’, age=20}
User{name=‘王五’, age=91}
User{name=‘张三’, age=8}
User{name=‘李四’, age=44}

根据上述方法,完成去重+按照年龄大于40以后从小到大+只取前二

// 因为Arrays.asList() 返回的是Arrays的内部类ArrayList,操作remove,add会报错
List<User> users = new ArrayList(list);
list.stream().distinct().filter(user -> user.getAge() > 40)
		.sorted(Comparator.comparing(User::getAge)).limit(2)
		.forEach(user -> System.out.println(user));

User{name=‘李四’, age=44}
User{name=‘王五’, age=91}

7、max,min,sum,avg,count

IntSummaryStatistics num = list.stream().mapToInt(u -> u.getAge()).summaryStatistics();
System.out.println("总共人数:" + num.getCount());
System.out.println("平均年龄:" + num.getAverage());
System.out.println("最大年龄:" + num.getMax());
System.out.println("最小年龄:" + num.getMin());
System.out.println("年龄之和:" + num.getSum());

总共人数:7
平均年龄:37.42857142857143
最大年龄:91
最小年龄:8
年龄之和:262

8、map():接收一个方法作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素

// 只输出所有人的年龄
list.stream().forEach(user -> System.out.println(user));
System.out.println("映射后----->");
List<Integer> ages = list.stream().map(user -> user.getAge()).collect(Collectors.toList());
ages.forEach(age -> System.out.println(age));

// 小写转大写
List<String> words = Arrays.asList("aaa", "vvvv", "cccc");
System.out.println("全部大写---->");
List<String> collect = words.stream().map(str -> str.toUpperCase()).collect(Collectors.toList());
collect.forEach(s -> System.out.println(s));

User{name=‘张三’, age=11}
User{name=‘王五’, age=20}
User{name=‘王五’, age=91}
User{name=‘张三’, age=8}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
User{name=‘李四’, age=44}
映射后----->
11
20
91
8
44
44
44
全部大写---->
AAA
VVVV
CCCC

9、flatMap():对每个元素执行mapper指定的操作,并用所有mapper返回的Stream中的元素组成一个新的Stream作为最终返回结果,通俗易懂就是将原来的stream中的所有元素都展开组成一个新的stream

// 创建一个 装有两个泛型为integer的集合
Stream<List<Integer>> stream = Stream.of(Arrays.asList(1, 2, 3), Arrays.asList(4, 5));
// 将两个合为一个
Stream<Integer> integerStream = stream
		.flatMap((Function<List<Integer>, Stream<Integer>>) integers -> integers.stream());
// 为新的集合
List<Integer> collect = integerStream.collect(Collectors.toList());
System.out.println("新stream大小:" + collect.size());
System.out.println("-----合并后-----");
collect.forEach(o -> System.out.println(o));

新stream大小:5
-----合并后-----
1
2
3
4
5

10、findFirst() :使用该方法获取第一个元素

User user = list.stream().findFirst().get();
System.out.println(user);

User{name=‘张三’, age=11}

11、reduce() :多面手

reduce 操作可以实现从一组元素中生成一个值
sum()、max()、min()、count()等都是reduce操作,将他们单独设为函数只是因为常用

例如:找到年龄最大的

Optional<User> reduce = list.stream().reduce((s1, s2) -> s1.getAge() > s2.getAge() ? s1 : s2);
User user = reduce.get();
System.out.println(user);

Optional<User> max = list.stream().max(Comparator.comparing(User::getAge));
System.out.println(max.get());

User{name=‘王五’, age=91}
User{name=‘王五’, age=91}

例如:求所有人的年龄和

// 求年龄之和
Integer reduce = list.stream().reduce(0, // 该参数为初始值
    (integer, user) -> integer + user.getAge(), // 该参数为累加器,新元素如何累加
    (integer, integer2) -> integer + integer2);// 多个部分如何合并
System.out.println(reduce);

262

12、使用collect()做字符串join

// 使用Collectors.joining()拼接字符串
Stream<String> stream = Stream.of("张三", "李四", "王五", "赵六");
Stream<String> stream1 = Stream.of("张三", "李四", "王五", "赵六");
Stream<String> stream2 = Stream.of("张三", "李四", "王五", "赵六");
String s = stream.collect(Collectors.joining()); // 张三李四王五赵六
String s1 = stream1.collect(Collectors.joining("-")); // 张三-李四-王五-赵六
String s2 = stream2.collect(Collectors.joining("-", "(", ")")); // (张三-李四-王五-赵六)
System.out.println(s);
System.out.println(s1);
System.out.println(s2);

张三李四王五赵六
张三-李四-王五-赵六
(张三-李四-王五-赵六)

参考文献:https://github.com/CarpenterLee/JavaLambdaInternals/blob/master/4-Streams%20API(I).md

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值