Stream API 中提供了findFirst(),orElse() 这样的 method, 这些 method 具体是做什么,可以看看文档:一目了然。
public static void main(String... args){ List<Integer> values = Arrays.asList(11,22,33,44,55,60,75); System.out.println(values.stream() .filter(i -> i%5 == 0) .map(i -> i*2) .findFirst() .orElse(0) ); }
findFirst(): 它是一个 terminal operator
/** * Returns an {@link Optional} describing the first element of this stream, * or an empty {@code Optional} if the stream is empty. If the stream has * no encounter order, then any element may be returned. * * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting * terminal operation</a>. * * @return an {@code Optional} describing the first element of this stream, * or an empty {@code Optional} if the stream is empty * @throws NullPointerException if the element selected is null */ Optional<T> findFirst();
orElse():
/** * Return the value if present, otherwise return {@code other}. * * @param other the value to be returned if there is no value present, may * be null * @return the value, if present, otherwise {@code other} */ public T orElse(T other) { return value != null ? value : other; }
这里举这个 demo 是想说明什么问题呢,现在说 Java 比之前更 efficient ,为什么这么说呢,一点一点分析:我们 demo 示例里的 code 如果我们用 jdk1.7 来实现是这样的:
public static void main(String... args){ List<Integer> values = Arrays.asList(11,22,33,44,55,60,75); System.out.println(values.stream() .filter(i -> i%5 == 0) .map(i -> i*2) .findFirst() .orElse(0) ); int result = 0; for (int i: values) { if(i % 5 == 0){ result = i*2; break; } } System.out.println(result); }两次 output 是相同的。
如果从表面上看,jdk1.7的 implementation 看上去好像比 Stream API 的 efficient 要高一点,因为 jdk1.7里第一个 value 满足条件后就直接 break 了,而 Stream API里呢,它是要先把所有的 number 都检查一遍,看能不能被5整除,再都乘以2,最后再去取第一个,如果找不到就是输出0. 反了? 真的是这样么? Stream API 反而让 Java 的 efficient 变低了,哈哈,不要被表面给欺骗了。其实不是这样的。Stream API 不会这么愚蠢的,可是从 code 上面看,java code 从上而下编译执行,应该就是像我刚说的那样很笨的 execute 才对,现在去推翻它。我们给上面的代码加点东西:
public static void main(String... args){ List<Integer> values = Arrays.asList(11,22,33,44,55,60,75); System.out.println(values.stream() .filter(Java8Demo::isDivisible) .map(Java8Demo::mapDouble) .findFirst() .orElse(0) ); } public static boolean isDivisible(int i){ System.out.println("in isDvs: " + i); return i % 5 == 0; } public static int mapDouble(int i){ System.out.println("in mapDouble: " + i); return i * 2; }看最终输出的:
in isDvs: 33
in isDvs: 44
in isDvs: 55
in mapDouble: 55
110
看到了吧,也是一样的,找到第一个满足条件的 number 后就不会再去往后面找了。很清楚吧。
解释一下:
我觉得下面这段英文解释的非常到位:
A stream supports two types of operations:
- Intermediate operations
- Terminal operations
Intermediate operations are also called lazy operations.
Terminal operations are also called eager operations.
A lazy operation does not process the elements until an eager operation is called on the stream.
An intermediate operation on a stream produces another stream.
Streams link operations to create a stream pipeline.
所以:
In the above code filter() and map() are all lazy operations. While reduce() is eager operation.
Stream API 的efficient 是要比 jdk1.7要高的,而且上面的 code 中使用的internal iteration,所以你 get 到 主要的 point 了么?
更多请参考这里:
http://docs.oracle.com/javase/8/docs/api/
http://www.java2s.com/Tutorials/Java_Streams/Tutorial/Streams/Intermediate_operations_Terminal_operations.htm