1. Stream简介
流(Stream)是Java SE 8中新增的API之一,它是一种处理数据流的技术,能够节省内存的使用并提高计算的效率。Stream API允许我们以声明性方式处理集合中的元素,而不用关心底层的实现细节。
Java 9对Stream API进行了一些改进,包括增加了一些新的操作符和调整了一些现有的操作符。在本文中,我们将讨论如何在Java 9中使用Stream API进行操作。
2. 创建Stream
2.1 从集合创建
在Java 9中,我们可以使用Stream.ofNullable()
方法创建一个流,并将集合作为参数传入。这个方法可以处理集合中可能存在的null
值,可以避免空指针异常。
下面是一个从集合创建的例子:
List<String> list = Arrays.asList("apple", "banana", "orange");
Stream<String> stream = Stream.ofNullable(list);
此外,我们还可以使用List.stream()
和Arrays.stream()
方法从集合创建一个流:
List<String> list = Arrays.asList("apple", "banana", "orange");
Stream<String> stream1 = list.stream();
Stream<String> stream2 = Arrays.stream(new String[]{"apple", "banana", "orange"});
2.2 从数组创建
我们可以使用IntStream.of()
和IntStream.range()
方法从数组创建一个流。其中,IntStream.of()
方法可以传入一个整型数组,并创建一个流,IntStream.range()
方法可以传入一个起始值和一个结束值,并创建一个流。
下面是一个从数组创建的例子:
int[] values = {1,2,3,4,5,6,7,8,9,10};
// 从整型数组创建流
IntStream stream1 = IntStream.of(values);
// 从指定范围的整型数列创建流
IntStream stream2 = IntStream.range(1, 11);
2.3 从函数创建
我们可以使用Stream.Iterate()
方法和Stream.Generate()
方法从函数创建一个流。其中,Stream.Iterate()
方法可以传入一个起始值和一个Lambda表达式,并利用这个Lambda表达式生成一个无限流。而Stream.Generate()
方法可以传入一个Lambda表达式,并利用这个表达式生成一个无限流。
下面是一个从函数创建的例子:
// 从0开始生成,每次加2,生成无限整型流
Stream<Integer> stream1 = Stream.iterate(0, n -> n + 2);
// 生成10个随机的double类型值
Stream<Double> stream2 = Stream.generate(Math::random).limit(10);
3. 中间操作
中间操作是指在流的数据元素上进行某种计算,并返回一个新的流,以便可以进行后续的操作。其中,中间操作又分为两种:
无状态操作:每个元素的运算不依赖于流中的其他元素
有状态操作:每个元素的运算有可能依赖于流中的其他元素
3.1 无状态操作
Java 9在Stream API中引入了三个新的无状态操作符:dropWhile()、takeWhile()和iterate()。我们将在下面进行介绍。
3.1.1 dropWhile()
该方法的作用是,从流中按照条件删除元素,直到条件不满足为止。这个操作符类似于skip()
,但它可以用一个Predicate
来指定删除条件。
下面是一个使用dropWhile()
方法的例子:
Stream<String> stream = Stream.of("apple", "banana", "orange", "peach");
stream.dropWhile(s -> s.length() < 6).forEach(System.out::println);
// 输出 banana orange peach
3.1.2 takeWhile()
该方法的作用是,从流中按照条件选择元素,直到条件不满足为止。它类似于filter()
方法,但它可以用一个Predicate
来指定选择条件。
下面是一个使用takeWhile()
方法的例子:
Stream<String> stream = Stream.of("apple", "banana", "orange", "peach");
stream.takeWhile(s -> s.length() < 6).forEach(System.out::println);
// 输出 apple banana
3.1.3 iterate()
该方法的作用是,生成一个无限流,每个元素都根据上一个元素进行计算。这个方法可以根据给定的初始值,以及一个UnaryOperator来生成一个流。例如,下面的代码可以生成一个从1开始的无限流,每个元素都是上一个元素的两倍:
Stream.iterate(1, n -> n << 1).limit(10).forEach(System.out::println);
// 输出 1 2 4 8 16 32 64 128 256 512
3.2 有状态操作
有状态操作符,每个元素的运算都有可能依赖于流中的其他元素,因此它们必须保持与流中的其他元素的状态。
3.2.1 flatMap()
flatMap()
方法可以将一个流中的每个元素映射为一个流,并将这些子流中的元素合并到一个新的流中。
下面是一个使用flatMap()
方法的例子:
Stream<String> stream = Stream.of("hello", "world");
stream.flatMap(s -> Stream.of(s.split(""))).forEach(System.out::println);
// 输出 h e l l o w o r l d
3.2.2 reduce()
reduce()
方法可以将流中的所有元素按照指定的方式进行运算,并返回结果。
下面是一个使用reduce()
方法的例子:
Stream<String> stream = Stream.of("apple", "banana", "orange", "peach");
Optional<String> str = stream.reduce((s1, s2) -> s1 + "-" + s2);
str.ifPresent(System.out::println);
// 输出 apple-banana-orange-peach
3.2.3 collect()
collect()
方法可以将流中的所有元素收集到一个集合中。
下面是一个使用collect()
方法的例子:
Stream<String> stream = Stream.of("apple", "banana", "orange", "peach");
List<String> list = stream.collect(Collectors.toList());
System.out.println(list);
// 输出 [apple, banana, orange, peach]
4. 总结
Stream API是Java 8中最重要的新功能之一,它提供了一种高效的方式来处理集合和数组。Java 9进一步改进了Stream API,增加了一些新的操作符,并优化了一些现有的操作符。在实际的开发过程中,我们可以根据需求灵活地使用Stream API,从而提高代码的可读性和维护性。