1. 使用
1.1. Stream流的生产
在Java中,有多种方式可以创建Stream对象,比如通过集合类的stream()方法,通过Arrays类的stream()方法,以及通过Stream类的of()、iterate()、generate()等方法。
- 集合类的stream方法
ini
代码解读
复制代码
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();
- Arrays类的stream()方法
ini
代码解读
复制代码
String[] array={"a", "b", "c"};
Stream<String> stream = Arrays.stream(array);
- Stream类的of()、iterate()、generate()等方法
arduino
代码解读
复制代码
Stream<String> stream = Stream.of("a", "b", "c");
1.2. Stream流的中间操作
Stream API提供了两种类型的操作方法,分别是中间操作和终结操作。中间操作用于对数据进行转换、过滤、排序等处理,而终结操作则用于触发执行中间操作得到的结果。
- map():将流中的元素作为入参,处理后生产一个新的元素
rust
代码解读
复制代码
List<String> list = Arrays.asList("a", "b", "c");
List<String> list2 = list.stream().map(str -> "new_" + str);
// 处理后
list 为 ["a", "b", "c"]
list2 为 ["new_a", "new_b", "new_c"]
- peek(): 将流中的元素作为入参,进行一些处理,正如peek的中文翻译“窥视”一样,peek操作主要进行一些辅助操作,例如打点。
ini
代码解读
复制代码
List<String> list = Arrays.asList("a", "b", "c");
list.stream().peek(System.out::println).collect(Collectors.toList());
- filter(): 过滤,只保留符合条件的元素
ini
代码解读
复制代码
List<String> list = Lists.newArrayList("1", "2", "3", "4", "5", "6");
List<String> list2 = strings.stream().filter(s -> Integer.parseInt(s) > 3).collect(Collectors.toList());
// 处理后
list 为 [1, 2, 3, 4, 5, 6]
list2 为 [4, 5, 6]
- sorted(): 对流中的元素进行排序
ini
代码解读
复制代码
List<String> strings = Lists.newArrayList("1", "3", "6", "4", "5", "2");
List<String> collect = strings.stream().sorted(String::compareTo).collect(Collectors.toList());
System.out.println(strings);
System.out.println(collect);
// 输出
[1, 3, 6, 4, 5, 2]
[1, 2, 3, 4, 5, 6]
- distinct():去除重复数据
ini
代码解读
复制代码
List<String> strings = Lists.newArrayList("1", "3", "3", "3", "5", "2");
List<String> collect = strings.stream().distinct().collect(Collectors.toList());
System.out.println(strings);
System.out.println(collect);
// 输出
[1, 3, 3, 3, 5, 2]
[1, 3, 5, 2]
- skip():跳过前几个元素
ini
代码解读
复制代码
List<String> strings = Lists.newArrayList("1", "3", "3", "3", "5", "2");
List<String> collect = strings.stream().skip(3).collect(Collectors.toList());
System.out.println(strings);
System.out.println(collect);
// 输出
[1, 3, 3, 3, 5, 2]
[3, 5, 2]
- limit():只保留前几个元素
ini
代码解读
复制代码
List<String> strings = Lists.newArrayList("1", "3", "3", "3", "5", "2");
List<String> collect = strings.stream().limit(3).collect(Collectors.toList());
System.out.println(strings);
System.out.println(collect);
// 输出
[1, 3, 3, 3, 5, 2]
[1, 3, 3]
1.3. Stream的终结操作
在上一节的代码示例中,所有操作都有一个collect()方法,这个就是Stream的终结操作。
Stream流的终结操作是在执行操作链后,产生最终结果的操作。它会触发流的遍历和处理,并返回一个最终的结果,例如集合、列表、数组等。在Java中,Stream流的终结操作通常会返回一个集合对象或者一个值。
常用的Stream流的终结操作包括:
- forEach:对流中的每个元素执行指定的操作。
- collect:将流中的元素收集到一个集合中,例如List、Set、Map等。
- reduce:根据指定的规则对流中的元素进行归约操作,返回一个值。
- max和min:找出流中的最大值或最小值。
- count:返回流中元素的数量。
- anyMatch、allMatch和noneMatch:判断流中的元素是否满足指定条件。
- findFirst和findAny:返回流中的第一个元素或任意一个元素。
- toArray:将流中的元素转换成数组。
通过终结操作,可以对流进行遍历和处理,并得到最终的结果。在使用终结操作时,需要注意流只能被消费一次,也就是说一旦对流进行了终结操作,就不能再使用该流进行其他操作了。因此,在使用终结操作前,需要确保已经完成了所有需要的中间操作。
2. 并行流
Java中的并行流是一种流操作的方式,它是使用多线程并行处理数据的一种机制。并行流可以在处理大量数据时提高程序的性能,因为它可以将数据分成多个任务,并行处理这些任务,从而加快处理速度。
在Java中,我们通常使用Stream API来对集合进行操作。并行流可以通过调用集合的parallelStream()方法来创建。并行流可以在底层使用多线程来处理元素,从而提高处理大量数据的效率。
需要注意的是,并行流可能会带来线程安全的问题:
java
代码解读
复制代码
import java.util.ArrayList;
import java.util.List;
public class ParallelStreamIssue {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
for (int i = 0; i < 10; i++) {
numbers.add(i);
}
// 正常的并行处理
numbers.parallelStream().forEach(num -> {
System.out.println("Number: " + num + ", Thread: " + Thread.currentThread().getName());
});
// 并行处理可能导致的问题示例
List<Integer> doubleNumbers = new ArrayList<>();
numbers.parallelStream().forEach(num -> {
doubleNumbers.add(num * 2); // 并行处理可能导致线程安全问题
});
System.out.println("Double numbers: " + doubleNumbers);
}
}