数据流的不同类型

数据流可以从多种数据源创建,尤其是集合。ListSet支持新方法stream()parallelStream(),来创建串行流或并行流。并行流能够在多个线程上执行操作,它们会在之后的章节中讲到。我们现在来看看串行流:

Arrays.asList("a1", "a2", "a3")
    .stream()
    .findFirst()
    .ifPresent(System.out::println);  // a1

在对象列表上调用stream()方法会返回一个通常的对象流。但是我们不需要创建一个集合来创建数据流,就像下面那样:

Stream.of("a1", "a2", "a3")
    .findFirst()
    .ifPresent(System.out::println);  // a1

只要使用Stream.of(),就可以从一系列对象引用中创建数据流。

除了普通的对象数据流,Java8还自带了特殊种类的流,用于处理基本数据类型intlongdouble。你可能已经猜到了它是IntStreamLongStreamDoubleStream

IntStream可以使用IntStream.range()替换通常的for循环:

IntStream.range(1, 4)
    .forEach(System.out::println);
// 1
// 2
// 3

所有这些基本数据流都像通常的对象数据流一样,但有一些不同。基本的数据流使用特殊的lambda表达式,例如,IntFunction而不是FunctionIntPredicate而不是Predicate。而且基本数据流支持额外的聚合终止操作sum()average()

Arrays.stream(new int[] {1, 2, 3})
    .map(n -> 2 * n + 1)
    .average()
    .ifPresent(System.out::println);  // 5.0

有时需要将通常的对象数据流转换为基本数据流,或者相反。出于这种目的,对象数据流支持特殊的映射操作mapToInt()mapToLong()mapToDouble()

Stream.of("a1", "a2", "a3")
    .map(s -> s.substring(1))
    .mapToInt(Integer::parseInt)
    .max()
    .ifPresent(System.out::println);  // 3

基本数据流可以通过mapToObj()转换为对象数据流:

IntStream.range(1, 4)
    .mapToObj(i -> "a" + i)
    .forEach(System.out::println);
// a1
// a2
// a3

下面是组合示例:浮点数据流首先映射为整数数据流,之后映射为字符串的对象数据流:

Stream.of(1.0, 2.0, 3.0)
    .mapToInt(Double::intValue)
    .mapToObj(i -> "a" + i)
    .forEach(System.out::println);
// a1
// a2
// a3