本文转载自链接: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只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成。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
