1、什么是Stream
stream是支持数据处理操作的源生成的元素序列,添加了很多操作,如查找、过滤、分组、排序等,它不是一种数据结构,简言之,Stream提供了一套高效且易于使用的数据处理方式。
特点:
- 不存储元素;
- 不改变源对象,返回一个持有结果的新的Stream;
- 当有终端操作时才会执行。
2、Stream执行操作
2.1 创建Stream
集合创建
java8在Collecton接口中,提供了两个获取流的方法,也就是说凡是实现Collection接口的实现类,都可以通过这两个方法获取到Stream。
default Stream stream(); //返回一个顺序流。
default Stream parallelStream(); //返回一个并行流。
List<User> users = new ArrayList<>();
users.add(new User("Jack",9));
users.add(new User("Kreas",10));
users.add(new User("Marry",13));
users.add(new User("Timi",14));
Stream<User> stream = users.stream();
Stream<User> userStream = users.parallelStream();
数组创建
Java8 中的 Arrays 的静态方法 stream() 可以获取数组流,并且该方法生成的流是数值流而不是 Stream。补充一点使用数值流可以避免计算过程中拆箱装箱,提高性能。
int[] intArray = {1,2,3};
IntStream stream = Arrays.stream(intArray);
值创建
可以使用静态方法 Stream.of(), 通过显示值 创建一个流。它可以接收任意数量的参数。
public static Stream of(T… values) : 返回一个流。
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4);
通过文件生成
Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset());
通过Files.line方法得到一个流,并且得到的每个流是给定文件中的一行.
通过函数生成
iterator
Stream<Integer> stream = Stream.iterate(0, n -> n + 2).limit(5);
iterate方法接受两个参数,第一个为初始化值,第二个为进行的函数操作,因为iterator生成的流为无限流,通过limit方法对流进行了截断,只生成5个偶数。
generator
Stream<Double> stream = Stream.generate(Math::random).limit(5);
generate方法接受一个参数,方法参数类型为Supplier ,由它为流提供值。generate生成的流也是无限流,因此通过limit对流进行了截断。
2.2 Stream中间操作
Stream中间操作主要是对流进行操作,返回一个新的流,交给下一个操作使用。当中间操作有多个时,就会形成中间操作链,需要注意一点,如果只有中间操作,那这些操作并不会执行,只有在执行终端操作时,操作才会执行,这种方式叫做延迟加载或者惰性求值。
distinct()
去重操作
List<User> users = new ArrayList<>();
User user1 = new User("Jack", 9);
User user2 = new User("Kreas",10);
User user3 = new User("Marry",13);
User user4 = new User("Timi", 14);
users.add(user1);
users.add(user2);
users.add(user3);
users.add(user4);
users.add(user1);
users.stream().distinct().forEach(u -> System.out.println(u.getName()));
// Jack Kreas Marry Timi
filter
通过使用filter方法进行条件筛选,filter的方法参数为一个条件(过滤保留函数返回值为 true 的元素)
List<User> users = new ArrayList<>();
User user1 = new User("Jack", 9);
User user2 = new User("Kreas",10);
User user3 = new User("Marry",13);
User user4 = new User("Timi", 14);
users.add(user1);
users.add(user2);
users.add(user3);
users.add(user4);
users.stream().filter(u -> u.getAge() > 12)
.forEach(u -> System.out.println(u.getName()));
// Marry Timi
limit
通过limit方法指定返回流的个数,limit的参数值必须 >=0,否则将会抛出异常。通常与排序配合使用。
List<User> users = new ArrayList<>();
User user1 = new User("Jack", 9);
User user2 = new User("Kreas",10);
User user3 = new User("Marry",13);
User user4 = new User("Timi", 14);
users.add(user1);
users.add(user2);
users.add(user3);
users.add(user4);
users.stream().limit(2)
.forEach(u -> System.out.println(u.getName()));
// Jack Kreas
sorted
指定比较规则进行排序。
List<User> users = new ArrayList<>();
User user1 = new User("Jack", 9);
User user2 = new User("Kreas",17);
User user3 = new User("Marry",12);
User user4 = new User("Timi", 14);
users.add(user1);
users.add(user2);
users.add(user3);
users.add(user4);
users.stream().sorted(Comparator.comparing(User::getAge).reversed())
.forEach(u -> System.out.println(u.getName()));
// Kreas Timi Marry Jack
skip
跳过指定个数元素
List<User> users = new ArrayList<>();
User user1 = new User("Jack", 9);
User user2 = new User("Kreas",17);
User user3 = new User("Marry",12);
User user4 = new User("Timi", 14);
users.add(user1);
users.add(user2);
users.add(user3);
users.add(user4);
users.stream().skip(2)
.forEach(u -> System.out.println(u.getName()));
// Marry Timi
map
接收一个Function函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。也就是转换操作,map还有三个应用于具体类型方法,分别是:mapToInt,mapToLong和mapToDouble。这三个方法也比较好理解,比如mapToInt就是把原始Stream转换成一个新的Stream,这个新生成的Stream中的元素都是int类型。这三个方法可以免除自动装箱/拆箱的额外消耗。
List<User> users = new ArrayList<>();
User user1 = new User("Jack", 9);
User user2 = new User("Kreas",17);
User user3 = new User("Marry",12);
User user4 = new User("Timi", 14);
users.add(user1);
users.add(user2);
users.add(user3);
users.add(user4);
users.stream().map(user -> "欢迎 "+ user.getName())
.forEach(System.out :: println);
/**
欢迎 Jack
欢迎 Kreas
欢迎 Marry
欢迎 Timi
*/
flatMap
接收一个Function函数作为参数,将流中的每个值都转换成另一个流,然后把所有流连接成一个流。flatMap也有三个应用于具体类型的方法,分别是:flatMapToInt、flatMapToLong、flatMapToDouble,其作用于map的三个衍生方法相同。
List<String> wordList = Arrays.asList("Java 8", "Lambdas", "In", "Action");
List<String> strList = wordList.stream()
.map(w -> w.split(" "))
.flatMap(Arrays::stream)
.distinct()
.collect(Collectors.toList());
// [Java, 8, Lambdas, In, Action]
map(w -> w.split(" ")) 的返回值为 Stream<String[]>,想获取 Stream,可以通过flatMap方法完成 Stream ->Stream 的转换。
2.3 终端操作
foreach
内部迭代
users.stream().forEach(user -> System.out.println(user.getName()));
collect
收集、将流转换为其他形式,比如转换成List、Set、Map。collect方法是用Collector作为参数,Collector接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例。例举一些常用的
List<User> users = Lists.newArrayList();
users.add(new User(15, "A", ImmutableList.of("1元", "5元")));
users.add(new User(25, "B", ImmutableList.of("10元", "50元")));
users.add(new User(21, "C", ImmutableList.of("100元")));
//收集名称到List
List<String> nameList = users.stream().map(User::getName).collect(Collectors.toList());
//收集名称到List
Set<String> nameSet = users.stream().map(User::getName).collect(Collectors.toSet());
//收集到map,名字作为key,user对象作为value
Map<String, User> userMap = users.stream()
.collect(Collectors.toMap(User::getName, Function.identity(), (k1, k2) -> k2));
allMatch
匹配所有元素
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
if (integerList.stream().allMatch(i -> i > 3)) {
System.out.println("所有元素值都大于3");
} else {
System.out.println("并非所有元素值都大于3");
}
anyMatch
匹配其中一个
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
if (integerList.stream().anyMatch(i -> i > 3)) {
System.out.println("存在值大于3的元素");
} else {
System.out.println("不存在值大于3的元素");
}
noneMatch
全部不匹配
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
if (integerList.stream().noneMatch(i -> i > 3)) {
System.out.println("值都小于3的元素");
} else {
System.out.println("值不都小于3的元素");
}
其他终端操作
- Optional findFirst(); 返回当前流中的第一个元素。
- Optional findAny(); 返回当前流中的任意元素。
- long count(); 返回流中元素总数。
- Optional max(Comparator<? super T> comparator); 返回流中最大值。
- Optional min(Comparator<? super T> comparator); 返回流中最小值。
- T reduce(T identity, BinaryOperator accumulator); 可以将流中元素反复结合起来,得到一个值。 返回 T。这是一个归约操作。
参考博客:
https://blog.csdn.net/QiuHaoqian/article/details/120942134
https://blog.csdn.net/weixin_43966635/article/details/109113579