A java.util.Stream
represents a sequence of elements on which one or more operations can be performed. Stream operations are either intermediate or terminal. While terminal operations return a result of a certain type, intermediate operations return the stream itself so you can chain multiple method calls in a row. Streams are created on a source, e.g. a java.util.Collection
like lists or sets (maps are not supported). Stream operations can either be executed sequential or parallel.
stream 表示一个序列,在这个序列上可以执行一个或多个操作。流操作分为中间操作和最终操作两类,最终操作返回一个特定类型的结果,中间结果返回流对象,这样可以在同一行链式调用多个方法。创建stream要指定数据源,collection 例如list 、set(不支持map)。stream操作可以串行、也可以并行。
List<String> stringCollection = new ArrayList<>();
stringCollection.add("ddd2");
stringCollection.add("aaa2");
stringCollection.add("bbb1");
stringCollection.add("aaa1");
stringCollection.add("bbb3");
stringCollection.add("ccc");
stringCollection.add("bbb2");
stringCollection.add("ddd1");
stream 可以通过
Collection.stream()
or
Collection.parallelStream()
创建。
Filter
Filter accepts a predicate to filter all elements of the stream. This operation is intermediatewhich enables us to call another stream operation (forEach
) on the result. ForEach accepts a consumer to be executed for each element in the filtered stream. ForEach is a terminal operation. It's void
, so we cannot call another stream operation.
Filter 接受一个谓词过滤stream里的所有元素。filter是中间操作,其结果可以调用另一个操作。forEach 接受一个函数【函数式接口Consumer】,操作流对象里的每一个元素。forEach是最终操作。不能再调用另一个流操作。
// aaa2 aaa1
stringCollection.stream().filter((s) -> s.startsWith("a")).forEach(System.out::println);
Sorted
Comparator
.
// "aaa1", "aaa2"
stringCollection.stream().sorted().filter((s) -> s.startsWith("a")).forEach(System.out::println);
Keep in mind that
sorted
does only create a sorted view of the stream without manipulating the ordering of the backed collection. The ordering of
stringCollection
is untouched:
stringCollection
不会被修改。
// ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1
System.out.println(stringCollection);
Map
The intermediate operation map
converts each element into another object via the given function. The following example converts each string into an upper-cased string. But you can also use map
to transform each object into another type. The generic type of the resulting stream depends on the generic type of the function you pass to map
.
// "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1"
stringCollection.stream().map(String::toUpperCase).sorted((a, b) -> b.compareTo(a))
.forEach(System.out::println);
Match
Various matching operations can be used to check whether a certain predicate matches the stream. All of those operations are terminal and return a boolean result.
提供各种match匹配操作,用于检查指定的predicate是否匹配整个stream。所有的这些匹配操作是最终操作,返回boolean结果。 boolean anyStartsWithA = stringCollection.stream().anyMatch((s) -> s.startsWith("a"));
System.out.println(anyStartsWithA); // true
boolean allStartsWithA = stringCollection.stream().allMatch((s) -> s.startsWith("a"));
System.out.println(allStartsWithA); // false
boolean noneStartsWithZ = stringCollection.stream().noneMatch((s) -> s.startsWith("z"));
System.out.println(noneStartsWithZ); // true
Count
Count is a terminal operation returning the number of elements in the stream as a long
.
count是一个最终操作,返回stream中的元素个数,返回值是long类型。
long startsWithB = stringCollection.stream().filter((s) -> s.startsWith("b")).count();
System.out.println(startsWithB); // 3
Reduce 简化|规约 翻译都不好
This terminal operation performs a reduction on the elements of the stream with the given function. The result is an Optional
holding the reduced value.
reduce操作是对流上的元素根据指定的函数执行reduction操作。结果是Optional,保存简化后的结果。
Optional<String> reduced = stringCollection.stream().sorted().reduce((s1, s2) -> s1 + "#" + s2);
// "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"
reduced.ifPresent(System.out::println);
ParallelStream
As mentioned above streams can be either sequential or parallel. Operations on sequential streams are performed on a single thread while operations on parallel streams are performed concurrent on multiple threads.
stream可以是串行也可以是并行的。串行stream单线程执行的,并行stream是多线程并行执行的。
public class ParallelStreamTest {
public static void main(String[] args) {
int max = 1000000;
List<String> values = new ArrayList<>(max);
for (int i = 0; i < max; i++) {
UUID uuid = UUID.randomUUID();
values.add(uuid.toString());
}
long t0 = System.nanoTime();
long count = values.stream().sorted().count();
System.out.println(count);
long t1 = System.nanoTime();
long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
System.out.println(String.format("sequential sort took: %d ms", millis));
long t2 = System.nanoTime();
long count2 = values.parallelStream().sorted().count();
System.out.println(count2);
long t3 = System.nanoTime();
long millis2 = TimeUnit.NANOSECONDS.toMillis(t3 - t2);
System.out.println(String.format("parallel sort took: %d ms", millis2));
}
}
结果大概差 50%。
1000000
sequential sort took: 1271 ms
1000000
parallel sort took: 560 ms