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的操作是线程安全的,不需要程序员自己进行线程同步。