JVM能够从循环中提升Java流吗?

JVM能够从循环中提升Java流吗?,java,performance,optimization,jvm,Java,Performance,Optimization,Jvm,我想知道JVM是否能够将流从循环中提升出来,例如在我写的这个交叉点检查中: for (SomeObject someObject:someObjects) { if (someList.stream().map(SomeObject::getValue).collect(Collectors.toList()) .contains(someObject.getValue())) { //do some error stuff } } 我有

我想知道JVM是否能够将流从循环中提升出来,例如在我写的这个交叉点检查中:

for (SomeObject someObject:someObjects) {
    if (someList.stream().map(SomeObject::getValue).collect(Collectors.toList())
            .contains(someObject.getValue())) {
        //do some error stuff
    }
}
我有必要这样重构它吗:

final List<Value> values = someList.stream().map(SomeObject::getValue).collect(Collectors.toList());
for (SomeObject someObject:someObjects) {
    if (values.contains(someObject.getValue()) {
        //do some error stuff
    }
}
final List values=someList.stream().map(SomeObject::getValue).collect(Collectors.toList());
对于(SomeObject SomeObject:someObjects){
if(values.contains(someObject.getValue()){
//做一些错误的事情
}
}

这样的代码看起来可能更好,但我只是想知道它是否会有很大的性能差异。

是的,第二个代码要好得多,在第一个代码中,您从头开始为每个“SomeObject”创建流。

我敢打赌“否”.AFAIK JVM不进行过程间优化。可能会有一些例外,但基本上,它一次只优化一个方法。为了让它真正有用,它依赖于内联,但您的表达式对于内联来说太复杂了


不管怎样,你的第二个片段

final List<Value> values = someList.stream().map(SomeObject::getValue).collect(Collectors.toList());
for (SomeObject someObject:someObjects) {
    if (values.contains(someObject.getValue()) {
        //do some error stuff
    }
}

为了节省收集时间。或者,更好的方法是,您可以使用
集合
进行更快的查找。

我看不出第一个版本不起作用的原因。您尝试过吗?请注意,如果您是lambda表达式的超级高手,您还可以使用
foreach
重写第一个
for
循环。是否需要处理每个over单独应用项?或者,一条错误消息就足够了吗?@Tim两者都很好,我只是想知道在一个大循环上这样做对性能的影响,更一般地说,JVM可以和不可以提升什么?我认为使用集合而不是列表会提高性能,在第二个代码块中,好的一点是@MatthieuThis我的直觉也是如此,但一些初步测试并没有显示性能上的任何差异。你能提供一些证据说明为什么需要这样做吗?@AdamBeddoe JVM/编译器可能足够聪明,可以意识到你的流列表与包含的循环不相关,并且知道足够多,可以将其拉出并只计算一次。但是,第二个版本是我认为您应该在这里使用的。@Adambeddo您确定您的性能测试是正确的吗?可能您的编译器或JIT刚刚将流移出循环以获得第一个代码示例?直观的流解决方案类似于:
if(someObjects.stream().anyMatch(someObject->someList.stream().anyMatch)(someListItem->someListItem.getValue().equals(someObject.getValue())){//do stuff;}
JVM肯定会进行“过程间优化”,即执行“积极的内联”作为应用任何其他优化之前的第一步。如果不这样做,那将是灾难性的。但是,在这个特定示例中,总体代码超过特定限制(最大代码大小、最大内联深度)的可能性很高流实现有安静的长调用链,Java 8的限制不是最新的…@Holger,我明白了,我应该重新制定我的答案…所有这些“过程间优化”实际上是“积极的内联”,然后是“过程内优化”。或者有任何例外,JVM可以为非内联方法做一些有用的事情吗?@Holger agresive inlining?这与内联不同吗?我第一次听说这个?而且JVM内部的代码已经稍微调整,以考虑到流,我记得我甚至对它发表了评论it@Holger我想是尤金“积极内联”是“投机内联”、“乐观内联”的总称,可能还有其他一些形式,它们的共同点是不能保证方法调用总是在已内联的方法上结束,因此必须插入回退来处理其他情况,甚至在以后可能会进行反优化。它还可以用来强调,它的应用不仅仅是为了消除e调用开销,但支持后续优化,这超过了任何与调用相关的成本。
...anyMatch(v -> v.equals(someObject.getValue())