为什么Java Stream中filter+findFirst+isPresent比anyMatch更快?
为什么filter+findFirst+isPresent比anyMatch执行更快?
最近写代码时,IntelliJ提示我把一段判断集合中是否存在特定元素的代码改成anyMatch。原代码是这样的:
boolean result1 = numbers.stream().filter(n -> { return n.number == 5; }).findFirst().isPresent();
IntelliJ建议的优化代码:
boolean result2 = numbers.stream().anyMatch(n -> { return n.number == 5; });
从功能上看anyMatch确实能实现需求,但实际测试后发现,原方法(filter+findFirst+isPresent)的速度几乎是anyMatch的两倍甚至更快。我不确定这是软硬件环境问题,还是对Stream API的理解有偏差,于是写了性能测试代码验证:
public class Main { public static void main(String[] args) { class TestObject { int number; TestObject(int num) { this.number = num; } } Set<TestObject> numbers = new HashSet<>(); Set<TestObject> numbers1 = new HashSet<>(); Set<TestObject> numbers2 = new HashSet<>(); for(int i = 0; i < 1000; i++) { numbers.add(new TestObject(i)); } for(int i = 0; i < 10000; i++) { numbers1.add(new TestObject(i)); } for(int i = 0; i < 100000; i++) { numbers2.add(new TestObject(i)); } Long start = System.nanoTime(); boolean result = numbers.stream().anyMatch(n -> { return n.number == 500; }); System.out.println("Time to find - anyMatch: " + (System.nanoTime() - start)); start = System.nanoTime(); result = numbers.stream().filter(n -> { return n.number == 500; }).findFirst().isPresent(); System.out.println("Time to find - filter + findFirst + isPresent: " + (System.nanoTime() - start)); start = System.nanoTime(); result = numbers1.stream().anyMatch(n -> { return n.number == 5000; }); System.out.println("Time to find - anyMatch: " + (System.nanoTime() - start)); start = System.nanoTime(); result = numbers1.stream().filter(n -> { return n.number == 5000; }).findFirst().isPresent(); System.out.println("Time to find - filter + findFirst + isPresent: " + (System.nanoTime() - start)); start = System.nanoTime(); result = numbers2.stream().anyMatch(n -> { return n.number == 50000; }); System.out.println("Time to find - anyMatch: " + (System.nanoTime() - start)); start = System.nanoTime(); result = numbers2.stream().filter(n -> { return n.number == 50000; }).findFirst().isPresent(); System.out.println("Time to find - filter + findFirst + isPresent: " + (System.nanoTime() - start)); } }
问题分析
你的性能测试存在几个关键问题,导致结果不准确:
- 缺少JVM预热:JVM的即时编译器(JIT)需要时间优化代码,首次运行的结果无法代表真实性能,应该先执行多轮预热测试。
- 单次测试误差大:单次运行的时间受系统环境波动影响明显,需多次运行取平均值才能得到可信结果。
- 测试代码笔误:原测试中判断5000和50000时,错误复用了
numbers集合而非对应的numbers1、numbers2,直接导致测试数据无效。
修正测试后会发现,anyMatch和filter+findFirst+isPresent的性能几乎一致——两者本质逻辑相同:都是遍历元素,找到第一个满足条件的元素就立即终止遍历。
你看到的速度差异,大概率是以下原因导致:
- JIT优化优先级:如果
filter+findFirst先被执行,JIT可能优先优化了这段代码,导致后续测试中它的表现更快。 - 未优化前的微小差异:
anyMatch作为终端操作,内部调用链比filter+findFirst+isPresent多一层包装,在JIT完成优化前可能有细微性能差距,但优化完成后这种差异会完全消失。
结论
从代码可读性和语义化角度,anyMatch更优——它直接表达了“是否存在任意匹配元素”的意图,而filter+findFirst+isPresent是间接实现该逻辑。性能上两者在JIT优化后无显著差异,你看到的速度差距基本是测试不规范带来的假象。
内容的提问来源于stack exchange,提问作者fooshy
相关产品推荐
相关产品推荐

