【发布时间】:2016-05-11 12:25:22
【问题描述】:
我正在尝试消化Stream 包,似乎很难理解。
我正在阅读Stream 包文档,并且在某个时候我尝试实现它以边做边学。这是我读过的文字:
中间操作返回一个新流。他们总是很懒惰; 执行诸如 filter() 之类的中间操作实际上并不 执行任何过滤,而是创建一个新流,当 遍历,包含初始流中匹配的元素 给定谓词。管道源的遍历直到 执行管道的终端操作。
我非常了解他们提供了一个新的Stream,所以我的第一个问题是,是否在不经过繁重操作的情况下创建流?
现在,由于中间操作是lazy,终端操作是eager,而且流比旧的if-else 编程标准更高效,并且更具可读性。
延迟处理流可以显着提高效率;在一个 管道,例如上面的 filter-map-sum 示例,过滤,映射, 和求和可以融合到数据的单次传递中,用最少的 中间状态。懒惰还允许避免检查所有 不需要时的数据;对于诸如“找到第一个 超过 1000 个字符的字符串”,只需要检查 只需足够的字符串即可找到具有所需特征的字符串 无需检查源中可用的所有字符串。 (这 当输入流是无限的时,行为变得更加重要 而不仅仅是大。)
为了证明这一点,我开始实施一个小程序来理解这个概念。这是程序:
List<String> stringList = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
stringList.add("String" + i);
}
long start = System.currentTimeMillis();
Stream stream = stringList.stream().filter(s -> s.contains("99"));
long midEnd = System.currentTimeMillis();
System.out.println("Time is millis before applying terminal operation: " + (midEnd - start));
System.out.println(stream.findFirst().get());
long end = System.currentTimeMillis();
System.out.println("Whole time in millis: " + (end - start));
System.out.println("Time in millis for Terminal operation: " + (end - midEnd));
start = System.currentTimeMillis();
for (String ss1 : stringList) {
if (ss1.contains("99")) {
System.out.println(ss1);
break;
}
}
end = System.currentTimeMillis();
System.out.println("Time in millis with old standard: " + (end - start));
我已经多次执行这个程序,每次都证明我从中间操作创建一个新的流是一项繁重的任务。与中间操作相比,终端操作确实需要很少的时间。
总的来说,旧的if-else 模式比streams 更有效。所以,这里还有更多问题:
- 我是不是误会了什么?
- 如果我理解正确,为什么以及何时使用流?
- 如果我做错或理解错了,请您帮助澄清我的概念Package java.util.stream?
实际数字:
尝试 1:
Time is millis before applying terminal operation: 73
String99
Whole time in millis: 76
Time in millis for Terminal operation: 3
String99
Time in millis with old standard: 0
尝试 2:
Time is millis before applying terminal operation: 56
String99
Whole time in millis: 59
Time in millis for Terminal operation: 3
String99
Time in millis with old standard: 0
尝试 3:
Time is millis before applying terminal operation: 69
String99
Whole time in millis: 72
Time in millis for Terminal operation: 3
String99
Time in millis with old standard: 0
如果有帮助,这些是我的机器详细信息:
Memory: 11.6 GiB
Processor: Intel® Core™ i7-3632QM CPU @ 2.20GHz × 8
OS-Type: 64-bit
【问题讨论】:
-
stringList.stream().filter(s -> s.contains("99"));可能需要不到一微秒的时间——你不能像现在这样测量它。必读:stackoverflow.com/questions/504103/… -
imho :使用它来提高代码的可读性。此外,使用
Stream编写允许您轻松选择激活/停用并行计算,但它不会神奇地优化已经优化的代码.. -
我仍然认为基准测试没有意义。我认为你可以在这里制定一个经验法则。
If your task takes less than 1ms to complete, using a stream will not improve the performance. -
您只是通过创建一个对象来增加一些开销。您有一项不可衡量的任务,并且您正在为其增加开销。您需要回到绘图板上进行基准测试。
-
考虑非终结操作序列的一种方法类似于在将正则表达式重复应用于大量字符串之前“编译”正则表达式。是的,编译正则表达式需要几个周期,但是对编译进行基准测试没有意义——重要的是重复操作的性能。
标签: java java-8 java-stream