搜索
您的当前位置:首页正文

重走Java基础之Streams(一)

来源:知库网

Introduction

流表示一系列元素并支持不同类型的操作来对这些元素执行计算。在Java 8中,Collection接口有两种方法来生成Stream

  • 1)stream()和
  • 2) parallelStream()

流操作包括中间或终端。 中间操作返回一个流,所以我们可以链接多个中间操作而不使用分号。 终端操作是void的或返回非流结果。

Examples

Using Streams

Stream<String> fruitStream = Stream.of("apple", "banana", "pear", "kiwi", "orange");

fruitStream.filter(s -> s.contains("a"))
           .map(String::toUpperCase)
           .sorted()
           .forEach(System.out::println);

Output:

APPLE
BANANA
ORANGE
PEAR

上述代码执行的操作可以总结如下:

  1. Note 如果映射函数返回与其输入参数不同的类型,那么map()操作将返回具有不同泛型类型的流。 例如在一个Stream调用.map(String :: isEmpty)返回一个Stream<Boolean>

  2. NoteStream中定义的操作之所以被执行,是因为最后有终端操作。 假如没有终端操作,'Stream'将不被处理,因为'Stream'输出不被任何终端操作使用(省的浪费计算资源,所以很多书上称之为被动式foreach)。

Chained operations

操作(如上所示)链接在一起以形成可以被视为对数据的查询


Reusing Streams

一个Stream不能重复使用。 一旦调用任何中间或终端操作,“Stream”对象将变得不可用。 Stream代替地使用中间Stream对象以便将中间操作链接在一起通过一系列Stream操作来生成一个Stream对象作为中间对象,最后再调用这个生成的Stream对象来完成最终的操作,最后一步的操作只能进行一次,之后,此流已经没了(生命周期已结束)。

Example:

Stream<String> stream =
    Stream.of("d2", "a2", "b1", "b3", "c")
        .filter(s -> s.startsWith("a"));

stream.anyMatch(s -> true);  // The Stream has been used and is now consumed.
stream.noneMatch(s -> true); // IllegalStateException; stream was already used

Closing Streams

请注意,Stream通常不必关闭。仅需要关闭在IO通道上运行的流。 大多数Stream 型不对资源操作,因此不需要关闭。

Stream 应该关闭的示例用例是,当您从文件创建一个Stream 行时:

try(final Stream<String> lines = Files.lines(Paths.get("somePath"))){
    lines.forEach(System.out::println);
}
public Stream<String>streamAndDelete(Path path) throws IOException {
    return Files.lines(path)
        .onClose(()->someClass.deletePath(path));
}

运行处理程序只有在调用close() 方法时才会执行,例如通过try-with-resources:

Path myPath = Paths.get("somePath");

try(final Stream<String> lines = streamAndDelete(myPath)){
    lines.forEach(System.out::println);
}
Files.exists(myPath); // returns false

If close() isn't called, explicitly or implicitly, then the handler will not be called either:
如果没有明确或隐式地调用close(),那么处理程序不会被调用:

streamAndDelete(myPath)
    .forEach(System.out::println);
Files.exists(myPath); // returns true 

Processing Order

Example:

List<Integer> integerList = Arrays.asList(0, 1, 2, 3, 42); 

// sequential 
long howManyOddNumbers = integerList.stream()
                                    .filter(e -> (e % 2) == 1).count(); 

System.out.println(howManyOddNumbers); // Output: 2

并行模式允许在多个核上使用多个线程,但不能保证处理元素的顺序。

如果在顺序的 Stream 上虽然调用了多个方法,则不一定必须要调用每个方法。 例如,如果一个 Stream 被过滤,并且元素的数量减少到一,则不会发生对诸如sort的方法的后续调用。 这可以提高顺序的Stream的性能 - 这是一个并行的Stream不可能实现的优化。

Example:

// parallel
long howManyOddNumbersParallel = integerList.parallelStream()
                                            .filter(e -> (e % 2) == 1).count();
System.out.println(howManyOddNumbersParallel); // Output: 2

Top