文章目录
- 1. 简介
- 1.1 Stream流的概念
- 1.2 为什么需要使用Stream流
- 2. Stream流的创建
- 2.1 从集合创建Stream
- 2.2 从数组创建Stream
- 2.3 使用Stream.of方法创建Stream
- 2.4 使用IntStream, LongStream, DoubleStream创建Stream
- 3. Stream流的常用操作
- 3.1 filter操作
- 3.2 map操作
- 3.3 flatMap操作
- 3.4 distinct操作
- 3.5 limit操作
- 3.6 skip操作
- 3.7 sorted操作
- 4. Stream流的终止操作
- 4.1 forEach操作
- 4.2 toArray操作
- 4.3 reduce操作
- 4.4 collect操作
- 4.5 min, max, count, anyMatch, allMatch, noneMatch操作
- 4.6 findFirst, findAny操作
- 5. Stream流的并行处理
- 5.1 并行流的概念
- 5.2 创建并行流
- 5.3 并行流的使用注意事项
- 6.实战示例
- 实例1:过滤和转换
- 实例2:统计
- 实例3:查找
- 实例4:并行处理
1. 简介
1.1 Stream流的概念
在Java 8中,Stream流是一种新的数据处理方式。Stream流并不是数据结构,它不会改变源数据,你可以视为遍历数据的高级迭代器。此外,Stream流可以透明地并行处理,无需我们在代码中手动进行并行处理。
Stream流的操作可以分为两种:中间操作和终止操作。中间操作只对数据做标记,只有在遇到终止操作时才会进行实际的计算。
List<String> list = Arrays.asList("a", "b", "c");
list.stream().filter(s -> s.startsWith("a")).forEach(System.out::println);
在上面的代码中,filter
是一个中间操作,forEach
是一个终止操作。
1.2 为什么需要使用Stream流
在Java 8之前,我们通常使用for循环或者迭代器对集合进行操作。然而,这种方式需要我们显式地在集合上进行迭代,这不仅代码冗长,而且在处理复杂的数据转换和过滤时,代码的可读性和维护性都会下降。
而Stream流提供了一种更高级、更方便的处理方式。它允许我们以声明性的方式处理数据,我们只需要告诉计算机我们想要的结果是什么,而不需要告诉它具体的实现步骤。这使得我们的代码更简洁,更易于阅读和维护。
此外,Stream流的另一个重要特性是它可以透明地进行并行处理。这意味着我们可以充分利用多核处理器的优势,而无需在代码中手动进行多线程管理。
总的来说,使用Stream流可以让我们的代码更简洁,更易于阅读和维护,同时能提高程序的性能。
2. Stream流的创建
在Java 8中,我们可以通过多种方式创建Stream流。以下是一些常见的方法:
2.1 从集合创建Stream
每个Java集合都可以通过stream
方法转换为Stream流。
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();
2.2 从数组创建Stream
我们可以使用Arrays.stream
方法从数组创建Stream流。
int[] array = {1, 2, 3, 4, 5};
IntStream stream = Arrays.stream(array);
2.3 使用Stream.of方法创建Stream
Stream.of
方法可以接受任意数量的参数,并返回一个Stream流。
Stream<String> stream = Stream.of("a", "b", "c");
2.4 使用IntStream, LongStream, DoubleStream创建Stream
Java 8引入了几种特殊的Stream流,用于处理基本数据类型的值,如IntStream
、LongStream
和DoubleStream
。这些特殊的Stream流提供了一些额外的方法,如sum
、average
等。
IntStream stream = IntStream.range(1, 5);
以上就是在Java 8中创建Stream流的一些常见方法。
3. Stream流的常用操作
在Java 8中,Stream流提供了一系列的操作,可以帮助我们更方便地处理数据。以下是一些常用的操作:
3.1 filter操作
filter
操作用于过滤Stream流中的元素。它接受一个Predicate接口类型的参数,只有满足该条件的元素才能获取。
List<String> list = Arrays.asList("a", "b", "c", "d", "e");
list.stream().filter(s -> s.startsWith("a")).forEach(System.out::println);
3.2 map操作
map
操作用于转换Stream流中的元素。它接受一个Function接口类型的参数,通过这个函数,我们可以将元素转换成其他类型。
List<String> list = Arrays.asList("a", "b", "c", "d", "e");
list.stream().map(String::toUpperCase).forEach(System.out::println);
3.3 flatMap操作
flatMap
操作用于将Stream流中的每个元素转换成另一个Stream流,然后将所有的Stream流连接成一个Stream流。
List<String> list = Arrays.asList("a", "b", "c", "d", "e");
list.stream().flatMap(s -> Stream.of(s.toUpperCase(), s.toLowerCase())).forEach(System.out::println);
3.4 distinct操作
distinct
操作用于去除Stream流中的重复元素。
List<String> list = Arrays.asList("a", "b", "c", "a", "b");
list.stream().distinct().forEach(System.out::println);
3.5 limit操作
limit
操作用于获取Stream流中的前n个元素。
List<String> list = Arrays.asList("a", "b", "c", "d", "e");
list.stream().limit(3).forEach(System.out::println);
3.6 skip操作
skip
操作用于跳过Stream流中的前n个元素。
List<String> list = Arrays.asList("a", "b", "c", "d", "e");
list.stream().skip(2).forEach(System.out::println);
3.7 sorted操作
sorted
操作用于对Stream流中的元素进行排序。它有两种形式:一种是使用自然顺序排序,另一种是使用自定义比较器排序。
List<String> list = Arrays.asList("a", "c", "b", "d", "e");
list.stream().sorted().forEach(System.out::println);
以上就是Java 8中Stream流的一些常用操作。
4. Stream流的终止操作
在Java 8中,Stream流的操作可以分为中间操作和终止操作。中间操作只对数据进行处理,但不会消费Stream流,而终止操作会消费Stream流,并产生一个结果或者一个副作用。以下是一些常用的终止操作:
4.1 forEach操作
forEach
操作用于对Stream流中的每个元素执行一个操作。这是一个终止操作,所以它会消费Stream流。
List<String> list = Arrays.asList("a", "b", "c");
list.stream().forEach(System.out::println);
4.2 toArray操作
toArray
操作用于将Stream流转换为数组。
List<String> list = Arrays.asList("a", "b", "c");
String[] array = list.stream().toArray(String[]::new);
4.3 reduce操作
reduce
操作用于将Stream流中的元素通过一个二元函数进行累积操作,从而将Stream流减少为一个单一的结果。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> sum = list.stream().reduce(Integer::sum);
4.4 collect操作
collect
操作用于将Stream流转换为其他形式的结果,如List、Set或Map。
List<String> list = Arrays.asList("a", "b", "c");
List<String> newList = list.stream().collect(Collectors.toList());
4.5 min, max, count, anyMatch, allMatch, noneMatch操作
这些操作用于对Stream流中的元素进行统计。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> min = list.stream().min(Integer::compareTo);
Optional<Integer> max = list.stream().max(Integer::compareTo);
long count = list.stream().count();
boolean anyMatch = list.stream().anyMatch(i -> i > 3);
boolean allMatch = list.stream().allMatch(i -> i > 0);
boolean noneMatch = list.stream().noneMatch(i -> i < 0);
4.6 findFirst, findAny操作
这些操作用于获取Stream流中的某个元素。
List<String> list = Arrays.asList("a", "b", "c");
Optional<String> first = list.stream().findFirst();
Optional<String> any = list.stream().findAny();
以上就是Java 8中Stream流的一些常用终止操作。
5. Stream流的并行处理
在Java 8中,Stream API支持并行处理,这是一种利用多核处理器的能力来加速计算的技术。
5.1 并行流的概念
并行流就是一个把内容分成多个数据块,并用不同的线程分别处理每个数据块的流。Java 8的并行流就是把一个数据内容分成多个数据块,并用多个线程处理的流。这样可以充分利用多核处理器的优势,使得程序在进行大数据量处理时能更快地得到结果。
5.2 创建并行流
创建并行流有两种方式:
- 使用
parallelStream
方法:
List<String> list = Arrays.asList("a", "b", "c", "d", "e");
Stream<String> parallelStream = list.parallelStream();
- 使用
parallel
方法:
List<String> list = Arrays.asList("a", "b", "c", "d", "e");
Stream<String> parallelStream = list.stream().parallel();
5.3 并行流的使用注意事项
虽然并行流可以提高处理速度,但并不是所有情况下都适用,并且并行流的使用也需要注意以下几点:
-
任务的性质:如果任务之间有大量的数据依赖性,那么并行流可能带来的性能提升就会大打折扣。
-
数据量的大小:只有在数据量足够大的情况下,使用并行流才能体现出性能优势。对于小数据量的处理,串行流可能更快。
-
并行处理可能引发的问题:并行处理可能会引发线程安全问题,需要确保操作是线程安全的。
-
并行流和顺序流的切换:并行流和顺序流可以相互切换。使用
parallel
方法可以将顺序流转换为并行流,使用sequential
方法可以将并行流转换为顺序流。 -
注意避免线程阻塞:如果流中的某些操作可能会阻塞线程,如网络IO操作,那么使用并行流可能会导致程序性能下降,甚至发生死锁。
以上就是Java 8中Stream流并行处理的一些基本概念和使用注意事项。
以下是一些使用Java 8 Stream流进行数据处理的实例:
6.实战示例
实例1:过滤和转换
假设我们有一个用户列表,我们想要找出年龄大于18岁的用户,并将他们的用户名转换为大写。
public class User {private String username;private int age;// getters and setters
}List<User> users = ... // 获取用户列表List<String> usernames = users.stream().filter(user -> user.getAge() > 18).map(User::getUsername).map(String::toUpperCase).collect(Collectors.toList());
实例2:统计
假设我们想要统计用户列表中年龄大于18岁的用户数量。
long count = users.stream().filter(user -> user.getAge() > 18).count();
实例3:查找
假设我们想要找到年龄最大的用户。
Optional<User> oldestUser = users.stream().max(Comparator.comparingInt(User::getAge));
实例4:并行处理
假设我们有一个非常大的用户列表,我们想要并行地处理这个列表,找出年龄大于18岁的用户,并将他们的用户名转换为大写。
List<String> usernames = users.parallelStream().filter(user -> user.getAge() > 18).map(User::getUsername).map(String::toUpperCase).collect(Collectors.toList());
以上就是一些使用Java 8 Stream流进行数据处理的实例。通过这些实例,我们可以看到Stream流提供了一种声明式的方式来处理数据,使得代码更加清晰和简洁。