目录
1.概述
Java Stream是Java 8引入的一种新特性,用于简化集合类的数据处理和操作。Stream API提供了一种流式处理的方式,可以对数据进行过滤、映射、聚合等操作,使得数据处理更加简洁、高效和易于理解。
stream中对数据的操作分为两类:
- 中间操作,对流的中间操作,即从流中取流。
- 中止操作,对流的最终操作,即从流中取值。
两种操作的代码示例:
int[] nums={1,2,3};
//map,中间操作,返回的是流
//sum,中止操作,返回的是最终结果
int sum= IntStream.of(nums).map(i->i*2).sum();
System.out.println(sum);
需要注意的一点是:中间操作都是惰性的,中止操作出现,才会真正执行中间操作。
以上面的例子来说,map操作虽然被率先调用了,但是在sum操作调用之前map操作其实是没有被执行的,sum操作调用后map才会执行。
2.流的创建
JDK8开始,JDK中带有多种创建stream的API:
//从集合中创建
List<String> list=new ArrayList<>();
list.stream();
list.parallelStream();
//从数组创建
Arrays.stream(new int[]{1,2,3});
//创建数字流
IntStream.of(1,2,3);
//创建无限流(根据传入的参数,截取指定长度)
new Random().ints().limit(10);
3.中间操作
3.1.清单
stream的中间操作,本质上就是对流进行加工,返回的是操作后的stream。
中间操作分为两种:
- 有状态,依赖于其他中间操作,必须等所依赖的其他中间操作完成后,才可执行。如排序,必须等所有其他还在进行的中间操作完成,才能进行排序。
- 无状态,不依赖于其他中间操作,自己玩自己的就行。
3.2.filter
filter(Predicate<T> predicate):根据给定的Predicate函数来过滤Stream中的元素。
List<Integer> list = Arrays.asList(1,2,3,4,5);
List<Integer> result = list.stream().filter(x -> x%2==0).collect(Collectors.toList());
// 输出结果为[2, 4]
3.3.map
map(Function<T, R> mapper):对Stream中的每个元素应用一个函数,返回一个新的Stream对象。
List<String> list = Arrays.asList("apple", "banana", "orange");
List<Integer> result = list.stream().map(x -> x.length()).collect(Collectors.toList());
// 输出结果为[5, 6, 6]
3.4.flatMap
flatMap(Function<T, Stream<R>> mapper):对Stream中的每个元素应用一个函数,将每个元素映射为一个新的Stream对象,然后将所有新的Stream对象合并成一个新的Stream对象。
List<List<Integer>> list = Arrays.asList(Arrays.asList(1, 2), Arrays.asList(3, 4), Arrays.asList(5, 6));
List<Integer> result = list.stream().flatMap(x -> x.stream()).collect(Collectors.toList());
// 输出结果为[1, 2, 3, 4, 5, 6]
3.5.distinct
distinct():去除Stream中的重复元素。
List<Integer> list = Arrays.asList(1, 2, 2, 3, 3, 4, 4, 5);
List<Integer> result = list.stream().distinct().collect(Collectors.toList());
// 输出结果为[1, 2, 3, 4, 5]
3.6.sorted
sorted():对Stream中的元素进行排序。
List<Integer> list = Arrays.asList(4, 2, 1, 3, 5);
List<Integer> result = list.stream().sorted().collect(Collectors.toList());
// 输出结果为[1, 2, 3, 4, 5]
3.7.peek
peek(Consumer<T> action):对Stream中的每个元素应用一个Consumer函数,返回一个新的Stream对象,与map类似,但是它不会改变元素的值。
List<Integer> list = Arrays.asList(1, 2, 3);
List<Integer> result = list.stream().peek(x -> x = x + 1).collect(Collectors.toList());
// 输出结果为[1, 2, 3]
3.8.limit
limit(long maxSize):截取Stream中的前maxSize个元素。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> result = list.stream().limit(3).collect(Collectors.toList());
// 输出结果为[1, 2, 3]
3.9.skip
skip(long n):跳过Stream中的前n个元素。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> result = list.stream().skip(3).collect(Collectors.toList());
// 输出结果为[4, 5]
4.中止操作
4.1.清单
在Java Stream API中,中止操作可以分为短路操作和非短路操作,它们的区别在于短路操作是最后一个操作,后面无法再跟任何操作,非短路操作后面还可以跟其他操作。
4.2.非短路操作
4.2.1.forEach
此操作可以迭代Stream中的每个元素,并对其进行操作。
List<String> list = Arrays.asList("Java", "is", "cool");
list.stream()
.forEach(System.out::println);
4.2.2.count
此操作可以返回Stream中元素的数量。
List<String> list = Arrays.asList("Java", "is", "cool");
long count = list.stream()
.filter(s -> s.length() > 2)
.count();
System.out.println(count);
4.2.3.reduce
此操作可以将Stream中的所有元素合并到一个结果中。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> result = list.stream()
.reduce((a, b) -> a + b);
System.out.println(result.get());
4.2.4.collect
此操作可以将Stream中的元素收集到一个集合中。
List<String> list = Arrays.asList("Java", "is", "cool");
List<String> result = list.stream()
.collect(Collectors.toList());
System.out.println(result);
4.2.5.max、min
此操作可以返回Stream中的最大或最小元素。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> max = list.stream()
.max(Integer::compareTo);
System.out.println(max.get());
4.3.短路操作
4.3.1.findFrist
返回Stream中的第一个元素。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> firstEven = numbers.stream()
.filter(n -> n % 2 == 0)
.findFirst();
if (firstEven.isPresent()) {
System.out.println("The first even number is " + firstEven.get());
} else {
System.out.println("No even numbers found.");
}
4.3.2.findAny
与findFirst()
相似,findAny()
也返回Stream中的一个元素,但是这个元素可以是任意一个,而不一定是第一个。在并行Stream中,findAny()
可能会返回任何一个符合条件的元素。与findFirst()
不同的是,findAny()
不保证返回的元素是Stream中的第一个符合条件的元素。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> anyEven = numbers.stream()
.filter(n -> n % 2 == 0)
.findAny();
if (anyEven.isPresent()) {
System.out.println("An even number is " + anyEven.get());
} else {
System.out.println("No even numbers found.");
}
4.3.3.allMatch
allMatch(Predicate<T> predicate)
:判断Stream中的所有元素是否都满足给定的Predicate条件。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean allEven = numbers.stream()
.allMatch(n -> n % 2 == 0);
if (allEven) {
System.out.println("All numbers are even.");
} else {
System.out.println("Some numbers are not even.");
}
4.3.4.anyMatch
anyMatch(Predicate<T> predicate)
:判断Stream中是否存在任意一个元素满足给定的Predicate条件。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean anyEven = numbers.stream()
.anyMatch(n -> n % 2 == 0);
if (anyEven) {
System.out.println("At least one number is even.");
} else {
System.out.println("No even numbers found.");
}
4.3.5.noneMatch
noneMatch(Predicate<T> predicate)
:判断Stream中是否没有任何元素满足给定的Predicate条件。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean noneNegative = numbers.stream()
.noneMatch(n -> n < 0);
if (noneNegative) {
System.out.println("All numbers are non-negative.");
} else {
System.out.println("Some numbers are negative.");
}
5.并行流
Java Stream提供了一种流式处理的方式,可以快速、方便地对集合、数组等数据进行处理和操作。而并行流则是Java Stream中的一种特殊类型的流,它可以自动将Stream中的数据分成多个小块,并在多个处理器上并行处理这些小块,以提高处理效率。
在Java 8之前,Java只能使用线程来实现并发编程。使用线程编程虽然可以实现并发执行,但是需要程序员自己管理线程的创建、调度和同步等问题,很容易引入死锁、竞争条件等问题。而在Java 8中引入了Stream API和并行流,使得并发编程变得更加容易和高效。
使用并行流的方式非常简单,只需要在创建Stream时调用parallel()
方法,就可以将Stream转换为并行流,如下所示:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> result = numbers.parallelStream() // 创建并行流
.map(n -> n * n) // 对每个元素进行平方运算
.collect(Collectors.toList()); // 将结果收集到列表中
System.out.println(result);
在上面的示例中,使用parallelStream()
方法创建一个并行流,并使用map()
方法对每个元素进行平方运算,最后使用collect()
方法将结果收集到一个列表中。
当列表中的元素数量很大时,使用并行流可以显著提高运行效率,因为并行流可以在多个处理器上并行处理元素。同时,Java Stream API的设计也保证了在并行执行时,Stream的操作是线程安全的,不需要程序员自己进行线程同步。