Java 8 引入了 Stream API,为处理集合数据提供了一种更便捷、高效的方式。Stream 流提供了一套丰富的 API,可以让开发者更简洁、优雅地处理数据。本文将介绍 Java Stream 流的基本概念、核心特性和常见用法,帮助您更好地理解和应用 Stream 流。
简介
Stream 是 Java 8 引入的一个概念,它代表了一系列元素的序列,支持各种操作来处理和转换这些元素。Stream 提供了一种流式处理的方式,可以通过链式调用操作方法来处理数据,而不需要显式地进行迭代或循环。
创建 Stream 流
Java 中的集合类可以通过 stream()
方法或 parallelStream()
方法来获取对应的 Stream 流。除此之外,还可以使用 Stream.of()
方法创建包含指定元素的流,或使用 Arrays.stream()
方法将数组转换为流。下面是一些例子:
-
从集合创建流: 假设我们有一个存储整数的
List
集合,我们可以使用stream()
方法从该集合创建一个流:List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); Stream<Integer> stream = numbers.stream();
-
从数组创建流: 如果我们有一个整数数组,可以使用
Arrays
类的stream()
方法来创建一个流:int[] array = {1, 2, 3, 4, 5}; IntStream stream = Arrays.stream(array);
-
使用
Stream.of()
方法创建流。Stream
类中的of()
方法允许我们直接传入多个元素来创建一个流:Stream<String> stream = Stream.of("apple", "banana", "orange");
-
使用
BufferedReader
从文件创建流: 我们可以使用 Java 的 IO 类来从文件中逐行读取内容并创建一个流:try (BufferedReader reader = new BufferedReader(new FileReader("data.txt"))) { Stream<String> stream = reader.lines(); // 处理流中的内容 } catch (IOException e) { e.printStackTrace(); }
Stream 流的操作方法
Stream 流提供了丰富的 API,可以分为两大类:中间操作和终端操作。中间操作可以用于转换和过滤流中的元素,而终端操作则用于产生最终结果或副作用。
- 中间操作:常见的中间操作包括
filter
、map
、flatMap
、distinct
、sorted
等。filter
方法用于根据条件筛选元素,map
方法用于对元素进行映射操作,flatMap
方法用于扁平化处理嵌套结构的流,distinct
方法用于去重,sorted
方法用于排序等。 - 终端操作:常见的终端操作包括
forEach
、collect
、reduce
、count
、min
、max
等。forEach
方法用于对流中的每个元素执行特定操作,collect
方法用于将流转换为其他数据结构,reduce
方法用于将流的元素合并为单个结果,count
方法用于计算流中的元素数量,min
和max
方法用于获取最小值和最大值等
filter
filter 操作用于根据给定的条件筛选流中的元素。假设我们有一个包含整数的 List
集合,我们想筛选出所有大于等于 10 的元素。我们可以使用 filter
操作来实现这个目标:
List<Integer> numbers = Arrays.asList(5, 10, 15, 20, 25, 30);
Stream<Integer> filteredStream = numbers.stream()
.filter(num -> num >= 10);
filteredStream.forEach(System.out::println);
在上述示例中,我们首先调用 numbers
集合的 stream()
方法来获取一个流。然后,我们使用 filter
操作,并提供一个 Lambda 表达式作为参数,该 Lambda 表达式指定了筛选条件(num >= 10)。最后,我们调用 forEach
终端操作来打印筛选后的结果。
输出结果将是:
10
15
20
25
30
通过使用filter操作,我们成功筛选出了所有大于等于10的元素,并打印出结果。
map
map 操作用于对流中的每个元素执行某种操作,并将操作的结果映射到一个新的流中。下面是一个使用 map 的例子:
假设我们有一个存储员工对象的 List
集合,每个员工对象包含姓名和年龄属性。我们想要将员工的姓名提取出来,并创建一个新的流来存储这些姓名。我们可以使用 map
操作来实现这个目标:
List<Employee> employees = Arrays.asList(
new Employee("Alice", 25),
new Employee("Bob", 30),
new Employee("Charlie", 35)
);
Stream<String> nameStream = employees.stream()
.map(Employee::getName);
nameStream.forEach(System.out::println);
在上述示例中,我们首先创建了一个包含员工对象的 List
集合。然后,我们使用stream()方法获取该集合的流。接下来,我们使用 map
操作,并传递一个方法引用(Employee::getName
),该方法引用表示对每个员工对象调用 getName
方法来获取姓名。最后,我们使用 forEach
终端操作来打印映射后的结果。
输出结果将是:
Alice
Bob
Charlie
通过使用 map
操作,我们成功将员工对象的姓名提取出来,并创建了一个新的流来存储这些姓名。
flatMap
flatMap
操作用于处理嵌套结构的流,并将其扁平化为单层流。下面是一个使用 flatMap
的例子:
假设我们有一个存储多个单词的 List 集合,每个单词又以空格分隔开。我们想要将这些单词拆分并创建一个包含所有单词的单层流。我们可以使用 flatMap
操作来实现这个目标:
List<String> words = Arrays.asList("Hello World", "Java Stream", "FlatMap Example");
Stream<String> flatMapStream = words.stream()
.flatMap(line -> Arrays.stream(line.split(" ")));
flatMapStream.forEach(System.out::println);
在上述示例中,我们首先创建了一个包含多个单词的 List
集合。然后,我们使用 stream()
方法获取该集合的流。接下来,我们使用 flatMap
操作,并传递一个 Lambda 表达式(line -> Arrays.stream(line.split(" "))
),该 Lambda 表达式表示将每行字符串拆分成单词,并创建一个单层流。最后,我们使用forEach 终端操作来打印拆分后的结果。
输出结果将是:
Hello
World
Java
Stream
FlatMap
Example
通过使用 flatMap 操作,我们成功将嵌套的流结构扁平化为一个单层流,并打印出拆分后的所有单词。
使用 flatMap
操作可以方便地处理嵌套的流结构,将其转换为单层流以便进行后续操作。这在处理嵌套集合、嵌套对象或多层数据结构时非常有用。
distinct
distinct
操作用于去除流中的重复元素,只保留不重复的元素。下面是一个使用 distinct
的例子:
假设我们有一个存储整数的 List
集合,其中包含一些重复的元素。我们想要创建一个新的流,只包含不重复的元素。我们可以使用 distinct
操作来实现这个目标:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 2, 3, 5, 1, 6);
Stream<Integer> distinctStream = numbers.stream().distinct();
distinctStream.forEach(System.out::println);
在上述示例中,我们首先创建了一个包含整数的 List
集合,其中包含一些重复的元素。然后,我们使用 stream()
方法获取该集合的流。接下来,我们使用distinct
操作来去除重复元素。最后,我们使用 forEach
终端操作来打印去重后的结果。
输出结果将是:
1
2
3
4
5
6
通过使用 distinct
操作,我们成功去除了流中的重复元素,并打印出不重复的结果。
使用 distinct
操作可以方便地去除流中的重复元素,确保流中的元素是唯一的。这在处理需要排除重复数据的场景下非常有用,例如去重操作或统计不重复元素的数量。
sorted
sorted
操作用于对流中的元素进行排序。下面是一个使用 sorted
的例子:
假设我们有一个存储整数的List集合,我们想要按照从小到大的顺序对这些整数进行排序。我们可以使用sorted操作来实现这个目标:
List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 3);
Stream<Integer> sortedStream = numbers.stream().sorted();
sortedStream.forEach(System.out::println);
在上述示例中,我们首先创建了一个包含整数的List集合。然后,我们使用 stream()
方法获取该集合的流。接下来,我们使用 sorted
操作对流中的元素进行排序,默认是按照自然顺序进行排序。最后,我们使用 forEach
终端操作来打印排序后的结果。
输出结果将是:
1
2
3
5
8
通过使用sorted操作,我们成功对流中的整数进行了排序,并打印出排序后的结果。
除了默认的自然排序外,我们还可以使用sorted操作的重载版本,传入一个Comparator来指定自定义的排序方式。这样可以根据具体的需求对流中的元素进行灵活的排序。
使用sorted操作可以方便地对流中的元素进行排序,无论是按照自然顺序还是自定义顺序。排序操作在许多场景中都是必需的,例如对数据进行升序或降序排列,或者根据特定的字段进行排序。
forEach
forEach
操作用于对流中的每个元素执行指定的操作。下面是一个使用 forEach
的例子:
假设我们有一个存储字符串的 List
集合,我们想要遍历并打印出每个字符串。我们可以使用 forEach
操作来实现这个目标:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream().forEach(System.out::println);
在上述示例中,我们首先创建了一个包含字符串的List集合。然后,我们使用 stream()
方法获取该集合的流。接下来,我们使用 forEach
操作,并传递一个方法引用(System.out::println
),该方法引用表示对每个元素调用 println
方法来打印字符串。最后,我们的操作是通过终端操作 forEach
来实际执行的。
输出结果将是:
Alice
Bob
Charlie
通过使用forEach操作,我们成功遍历了流中的每个元素并将其打印出来。
使用forEach操作可以对流中的每个元素执行指定的操作,例如打印、更新或其他自定义操作。它提供了一种简洁的方式来对流中的元素进行遍历和处理,无需显式使用循环结构。
collect
用于将流中的元素收集到一个容器或生成一个最终结果。它提供了许多常用的操作,以下是一些常见的collect
操作:
-
将流元素收集到
List
或ArrayList
:List<Integer> list = stream.collect(Collectors.toList());
-
将流元素收集到
Set
或HashSet
:Set<Integer> set = stream.collect(Collectors.toSet());
-
将流元素收集到指定的集合类型:
ArrayList<Integer> arrayList = stream.collect(Collectors.toCollection(ArrayList::new));
-
将流元素收集到
Map
:Map<Integer, String> map = stream.collect(Collectors.toMap(Employee::getId, Employee::getName));
-
将流元素分组,并将结果存储到
Map
中:可以使用 Stream 流进行分组操作。Stream 流提供了
groupingBy()
方法来实现分组。下面是一个示例代码,演示如何使用 Stream 流进行分组操作:
import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class GroupingExample { public static void main(String[] args) { // 创建一个包含多个字符串的列表 List<String> strings = Arrays.asList("apple", "banana", "apricot", "blueberry", "avocado"); // 使用 Stream 流进行分组,按照字符串的首字母进行分组 Map<Character, List<String>> groupedMap = strings.stream() .collect(Collectors.groupingBy(s -> s.charAt(0))); // 输出分组结果 groupedMap.forEach((key, value) -> System.out.println(key + ": " + value)); } }
运行上述代码,将会按照字符串的首字母进行分组,并输出分组结果。输出结果如下:
a: [apple, apricot, avocado] b: [banana, blueberry]
在上述示例中,我们使用了
groupingBy()
方法,以字符串的首字母作为分组的依据。groupingBy()
方法接受一个函数,用于指定按照哪个属性或条件进行分组。最终,我们将分组结果保存在一个Map
中,其中key
为分组的标准(这里是首字母),value
为对应的元素列表。 -
将流元素分区,并将结果存储到
Map
中:假设我们有一个存储
Employee
对象的流,每个Employee
对象包含id
和name
属性,我们想要将员工按照是否为经理进行分区,将经理和非经理分别存储到一个Map
中。我们可以使用partitioningBy
来实现这个目标:Map<Boolean, List<Employee>> partitionedEmployees = stream.collect(Collectors.partitioningBy(Employee::isManager));
在上述示例中,我们通过调用
partitioningBy
方法,并传入一个判断条件的方法引用(Employee::isManager
),将流中的元素按照是否为经理进行分区。partitioningBy
方法返回一个Map
,其中键为Boolean
类型,值为分区后的元素列表。假设我们的
Employee
类定义如下:class Employee { private int id; private String name; private boolean isManager; // 省略构造函数和其他方法 public boolean isManager() { return isManager; } }
假设流中包含以下员工对象:
Employee emp1 = new Employee(1, "Alice", true); Employee emp2 = new Employee(2, "Bob", false); Employee emp3 = new Employee(3, "Charlie", true); Employee emp4 = new Employee(4, "David", false);
执行
partitioningBy
操作后,将得到以下Map
结果:{ false=[Employee{id=2, name='Bob', isManager=false}, Employee{id=4, name='David', isManager=false}], true=[Employee{id=1, name='Alice', isManager=true}, Employee{id=3, name='Charlie', isManager=true}] }
在结果的
Map
中,键为false
的列表存储了非经理员工,键为true
的列表存储了经理员工。通过使用
partitioningBy
操作,我们可以根据一个条件将流元素分成两个部分,并将分区的结果存储到一个Map
中。这对于处理满足特定条件的元素非常有用,例如将数据分为两个不同的类别,根据条件进行过滤或处理。 -
将流元素连接成字符串:
String result = stream.collect(Collectors.joining(", "));
-
将流元素统计为汇总信息:
假设我们有一个存储
Employee
对象的流,每个Employee
对象包含salary
属性,我们想要统计员工的工资信息。我们可以使用summarizingInt
来实现这个目标:IntSummaryStatistics statistics = stream.collect(Collectors.summarizingInt(Employee::getSalary));
Collectors.summarizingInt
方法统计流中元素的汇总信息,并生成一个IntSummaryStatistics
对象,包含了元素的总数、总和、平均值、最大值和最小值等统计结果。在上述示例中,我们调用
summarizingInt
方法,并传入一个获取工资的方法引用(Employee::getSalary
)。summarizingInt
方法返回一个IntSummaryStatistics
对象,其中包含了流中元素的统计信息。假设我们的
Employee
类定义如下:class Employee { private int salary; // 省略构造函数和其他方法 public int getSalary() { return salary; } }
假设流中包含以下员工对象:
Employee emp1 = new Employee(5000); Employee emp2 = new Employee(6000); Employee emp3 = new Employee(7000); Employee emp4 = new Employee(5500);
执行
summarizingInt
操作后,将得到以下IntSummaryStatistics
结果:IntSummaryStatistics{count=4, sum=23500, min=5000, average=5875.000000, max=7000}
IntSummaryStatistics
对象提供了以下方法用于获取统计信息:getCount()
:返回元素的数量。getSum()
:返回元素的总和。getMin()
:返回元素的最小值。getAverage()
:返回元素的平均值。getMax()
:返回元素的最大值。
通过使用
summarizingInt
操作,我们可以方便地获取流中元素的汇总信息,包括总数、总和、平均值、最大值和最小值。这对于统计数据或了解数据分布非常有用。
流元素分组和分区的区别
下面,我们单独说说第 5 点所说的将流元素分组,并将结果存储到 Map
中 和第 6 点将流元素分区,并将结果存储到 Map
中的区别。
第 5 点中的操作是将流元素根据一个属性或函数的结果进行分组,并将分组的结果存储到Map
中。而第 6 点中的操作是根据一个条件将流元素进行分区,并将分区的结果存储到 Map
中。虽然两个操作都使用了Collectors
类的方法,并将结果存储到Map
中,但它们的目的和用法略有不同。
在第 5 点中,我们使用 Collectors.groupingBy
方法将流元素按照一个属性或函数的结果进行分组,生成一个 Map
,其中键为分组的依据,值为分组后的元素列表。这样的分组操作适用于将数据按照某个属性进行分类或归类,例如根据部门将员工进行分组。
在第 6 点中,我们使用 Collectors.partitioningBy
方法根据一个条件将流元素进行分区,生成一个 Map
,其中键为 Boolean
类型,值为分区后的元素列表。这样的分区操作适用于将数据根据一个条件进行分为两个部分,例如将员工按照是否为经理进行分区。
区别总结如下:
groupingBy
:根据属性或函数的结果进行分组,生成一个Map
,键为分组依据,值为分组后的元素列表。partitioningBy
:根据条件进行分区,生成一个Map
,键为Boolean
类型,值为分区后的元素列表。
因此,这两个操作在分组和分区的概念上略有不同,但都可以将流元素按照某种方式进行分类,并将结果存储到Map
中以供后续处理。具体使用哪种操作取决于业务需求和分组/分区的条件。
summarizingInt 与 summingInt
在第 8 点中,我们使用 summarizingInt
将流元素统计为汇总信息。Collectors
还有一个很类似的方法 summingInt
,我们来聊聊它们之间的区别:
summarizingInt
操作使用IntSummaryStatistics
类来收集统计信息,它提供了更全面的汇总结果,包括总数、总和、平均值、最大值和最小值等。它返回的是一个IntSummaryStatistics
对象,可以通过该对象的方法获取统计结果。summingInt
操作只计算元素的总和,返回的是一个Integer
类型的结果,表示所有元素的累加和。
下面是两个操作的示例用法和结果对比:
使用summarizingInt
进行统计:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
IntSummaryStatistics statistics = numbers.stream().collect(Collectors.summarizingInt(Integer::intValue));
IntSummaryStatistics
结果:
IntSummaryStatistics{count=5, sum=15, min=1, average=3.000000, max=5}
使用summingInt
进行统计:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream().collect(Collectors.summingInt(Integer::intValue));
sum
结果:
15
总结:
summarizingInt
提供了更全面的汇总信息,包括总数、总和、平均值、最大值和最小值等。summingInt
仅计算元素的总和,返回一个整数结果。
选择使用哪种操作取决于你需要的统计信息。如果你需要更详细的统计结果,包括平均值、最大值和最小值等,那么使用summarizingInt
更适合。如果只需要计算元素的总和,那么使用summingInt
更简洁高效。
reduce
reduce
用于将流中的元素进行累积、组合或聚合操作,生成一个最终的结果。它接受一个二元操作符(BinaryOperator)作为参数,用于指定元素的累积逻辑。
下面是一个使用 reduce
操作的示例:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 使用 reduce 操作求和
int sum = numbers.stream()
.reduce(0, (a, b) -> a + b);
System.out.println(sum);
在上述示例中,我们有一个包含整数的列表 numbers
。我们使用 reduce
操作将这些整数求和。初始值为 0,累积操作为将两个整数相加。
执行结果将输出:
15
在这个例子中,初始值为 0。reduce
操作遍历流中的元素,将初始值和流中的第一个元素相加得到中间结果,然后将中间结果和流中的下一个元素相加,以此类推,直到遍历完所有元素。最后的结果就是所有元素的和。
reduce
操作还有其他的用法,例如用于寻找最大值、最小值、拼接字符串等。通过提供不同的累积操作,可以根据具体需求进行自定义的累积逻辑。
注意,reduce
操作的结果是一个 Optional
类型,因为流可能为空。如果流为空,那么 reduce
操作的结果将是一个空的 Optional
。如果你确定流不会为空,也可以使用无初始值的重载方法 reduce(BinaryOperator accumulator)
,此时结果将直接是一个具体的值。
总结:reduce
操作用于将流中的元素进行累积、组合或聚合操作。它接受一个二元操作符作为参数,并根据累积逻辑对流中的元素进行操作,生成最终的结果。
min
当使用 min
操作时,Stream 流会根据给定的比较器(Comparator)或元素的自然顺序,返回流中的最小元素。下面是一个使用 min
操作找到最小整数的例子:
List<Integer> numbers = Arrays.asList(5, 2, 9, 1, 7);
// 找到最小整数
Optional<Integer> minNumber = numbers.stream()
.min(Integer::compareTo);
if (minNumber.isPresent()) {
System.out.println("最小整数是: " + minNumber.get());
} else {
System.out.println("流为空,无最小整数。");
}
在上述示例中,我们有一个包含整数的列表 numbers
。我们使用 min
操作查找列表中的最小整数。我们传递 Integer::compareTo
作为比较器来确定最小值。
执行结果将输出:
最小整数是: 1
在这个例子中,min
操作将遍历流中的元素,并使用比较器或自然顺序来找到最小的整数。返回的结果是一个 Optional
类型,因为流可能为空。我们可以使用 isPresent()
方法来检查结果是否存在,并使用 get()
方法获取最小值。
如果流为空,那么 min
操作的结果将是一个空的 Optional
。
除了整数,min
操作也适用于其他类型的元素,只需要提供适当的比较器或确保元素的类型实现了 Comparable
接口。
总结:min
操作用于找到流中的最小元素,根据给定的比较器或元素的自然顺序进行比较。它返回一个 Optional
类型的结果,可以使用 isPresent()
和 get()
方法来检查和获取最小值。
max
当使用 max
操作时,Stream 流会根据给定的比较器(Comparator)或元素的自然顺序,返回流中的最大元素。下面是一个使用 max
操作找到最大整数的例子:
List<Integer> numbers = Arrays.asList(5, 2, 9, 1, 7);
// 找到最大整数
Optional<Integer> maxNumber = numbers.stream()
.max(Integer::compareTo);
if (maxNumber.isPresent()) {
System.out.println("最大整数是: " + maxNumber.get());
} else {
System.out.println("流为空,无最大整数。");
}
在上述示例中,我们有一个包含整数的列表 numbers
。我们使用 max
操作查找列表中的最大整数。我们传递 Integer::compareTo
作为比较器来确定最大值。
执行结果将输出:
最大整数是: 9
在这个例子中,max
操作将遍历流中的元素,并使用比较器或自然顺序来找到最大的整数。返回的结果是一个 Optional
类型,因为流可能为空。我们可以使用 isPresent()
方法来检查结果是否存在,并使用 get()
方法获取最大值。
如果流为空,那么 max
操作的结果将是一个空的 Optional
。
除了整数,max
操作也适用于其他类型的元素,只需要提供适当的比较器或确保元素的类型实现了 Comparable
接口。
总结:max
操作用于找到流中的最大元素,根据给定的比较器或元素的自然顺序进行比较。它返回一个 Optional
类型的结果,可以使用 isPresent()
和 get()
方法来检查和获取最大值。
sum
Java的流(Stream)API 提供了 sum()
方法,可用于对流中的数值类型进行求和。
下面是一个简单的示例,演示了如何使用流(Stream)来对整数列表进行求和:
import java.util.Arrays;
import java.util.List;
public class StreamSumExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.mapToInt(Integer::intValue)
.sum();
System.out.println("Sum: " + sum);
}
}
在上述示例中,我们首先创建了一个整数列表 numbers
,包含了 1 到 5 的整数。然后,我们使用 stream()
方法将列表转换为流(Stream)。接下来,我们使用mapToInt()
方法将流中的元素映射为整数类型。最后,我们使用 sum()
方法对整数流进行求和,并将结果存储在 sum
变量中。最后,我们打印出求和的结果。
请注意,使用 mapToInt()
方法将流转换为 IntStream
可以提高求和操作的性能,因为 IntStream
是针对整数类型的专门优化的流。
并行流
Java Stream 提供了 parallel()
方法,用于将流转换为并行流。并行流可以自动将操作并行化,利用多线程处理数据,从而提高处理速度。但是需要谨慎使用,并行流可能引发线程安全问题和性能损失。
要创建并行流,只需在流上调用 parallel()
方法即可,示例如下:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> sequentialStream = numbers.stream(); // 创建串行流
Stream<Integer> parallelStream = numbers.parallelStream(); // 创建并行流
在上述示例中,我们使用 stream()
方法创建了一个串行流 sequentialStream
,使用 parallelStream()
方法创建了一个并行流 parallelStream
。
并行流的使用方式与串行流类似,可以对其应用各种中间操作(如 filter
、map
、reduce
等)和终端操作(如 forEach
、collect
、count
等)来处理数据。
并行流的优势在于它可以充分利用多核处理器的并行计算能力,适用于大规模数据的处理。在某些场景下,使用并行流可以显著提升处理速度。
然而,使用并行流也需要注意一些问题:
- 并行流适用于执行耗时的操作,当操作简单且数据量较小时,并行化的开销可能会超过并行计算的收益。
- 并行流在处理过程中会涉及到多线程的调度和同步,因此需要确保代码是线程安全的。
- 某些操作(如有状态的中间操作)可能会导致并行流的性能下降,需要谨慎使用。
- 并行流的处理顺序可能与串行流不同,因为操作会以并发的方式执行。
以下是一个使用并行流的真实案例:计算列表中所有数字的平方和。
import java.util.Arrays;
import java.util.List;
public class ParallelStreamExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 串行流计算平方和
int sequentialSum = numbers.stream()
.mapToInt(n -> n * n)
.sum();
// 并行流计算平方和
int parallelSum = numbers.parallelStream()
.mapToInt(n -> n * n)
.sum();
System.out.println("串行流平方和: " + sequentialSum);
System.out.println("并行流平方和: " + parallelSum);
}
}
在上述示例中,我们有一个包含整数的列表 numbers
。首先,我们使用串行流 stream()
对列表进行处理,将每个元素映射为其平方值,然后使用 mapToInt
将流转换为 IntStream
,最后使用 sum()
方法计算平方和。
接下来,我们使用并行流 parallelStream()
对列表进行相同的处理操作,通过调用 parallelStream()
方法将流转换为并行流,并使用相同的操作链计算平方和。
运行以上代码,会得到以下输出:
串行流平方和: 55
并行流平方和: 55
可以看到,无论是使用串行流还是并行流,最终计算的平方和结果都是相同的。
标签:Stream,探索,stream,元素,算法,使用,Employee,操作 From: https://www.cnblogs.com/zn-pi/p/17490963.html基于 Spring Boot 2.7.12、MyBatis-Plus、Spring Security 等主流技术栈构建的后台管理系统:
后台:https://gitee.com/linjiabin100/pi-admin.git
前端:https://gitee.com/linjiabin100/pi-admin-web.git