数据流可以从多种数据源创建,尤其是集合。List
和Set
支持新方法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还自带了特殊种类的流,用于处理基本数据类型int
、long
和 double
。你可能已经猜到了它是IntStream
、LongStream
和 DoubleStream
。
IntStream
可以使用IntStream.range()
替换通常的for
循环:
IntStream.range(1, 4)
.forEach(System.out::println);
// 1
// 2
// 3
所有这些基本数据流都像通常的对象数据流一样,但有一些不同。基本的数据流使用特殊的lambda表达式,例如,IntFunction
而不是Function
,IntPredicate
而不是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