You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中使Lambda表达式性能接近或优于for循环的其他影响因素

Optimizing Lambda/Stream Performance to Match or Outperform For Loops

Great job running these performance tests on mutable vs immutable lists and different iteration patterns! You’ve already nailed some key factors—sorted lists, immutable collections, and the overhead of Optional—so let’s break down additional elements that can make Lambda/Stream-based code equal or even faster than traditional for loops:

Additional Performance Factors

  • Cut down on intermediate stream operations: Each intermediate step (like filter or map) adds small overhead. Combine multiple predicates into one filter, or skip unnecessary mappings, to reduce this cost. For example, a single filter(object -> object != null && object.getObject() != null) is better than chaining two separate filter calls.
  • Leverage primitive streams: Your test collects Integer IDs—using IntStream (via mapToInt) instead of Stream<Integer> eliminates auto-boxing and unboxing overhead, which is a big win for large datasets. Primitive streams are optimized to avoid wrapper class costs entirely.
  • Add JIT warm-up runs: The JVM’s Just-In-Time compiler optimizes code after it runs multiple times. If your test only executes once, streams might not get the full benefit of JIT optimizations. Running a few warm-up iterations before measuring time will give you a more realistic performance reading.
  • Minimize boxing/unboxing: Beyond primitive streams, avoid converting between primitives and their wrapper classes wherever possible. Use stream methods designed for primitives (e.g., sum() on IntStream instead of Collectors.summingInt()) to skip these costly conversions.
  • Optimize parallel stream usage: Your parallel stream already outperforms some for loops, but make sure your task is truly parallelizable (no shared mutable state, minimal synchronization). Also, parallel streams shine with large datasets—small datasets might not justify the thread setup and coordination overhead.
  • Use specialized collectors: Instead of generic Collectors.toList(), use targeted collectors like Collectors.toCollection(ArrayList::new) to avoid unnecessary type checks or intermediate allocations. For primitive values, collectors like Collectors.averagingLong() are optimized for performance.
  • Prefer method references over lambda expressions: Method references (e.g., MyObject::getId) can be slightly faster than anonymous lambdas (object -> object.getId()) because the JVM can cache these references more efficiently, reducing runtime overhead.

Your Test Execution Times

  • Enhanced For - 耗时:141ms
  • For - 耗时:109ms
  • Iterator - 耗时:125ms
  • Stream - 耗时:172ms
  • Parallel Stream - 耗时:94ms
  • Optional Stream - 耗时:156ms
  • Optional Parallel Stream - 耗时:140ms

Test Code

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

class MyObject {
    private Integer id;
    private String name;
    private String message;
    private MySecondObject object;

    public MyObject(Integer id, String name, String message, MySecondObject object) {
        this.id = id;
        this.name = name;
        this.message = message;
        this.object = object;
    }

    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }
    public MySecondObject getObject() { return object; }
    public void setObject(MySecondObject object) { this.object = object; }

    @Override
    public int hashCode() {
        int hash = 8;
        hash = 14 * hash + Objects.hashCode(this.id);
        hash = 14 * hash + Objects.hashCode(this.name);
        hash = 14 * hash + Objects.hashCode(this.message);
        hash = 14 * hash + Objects.hashCode(this.object);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) { return true; }
        if (obj == null) { return false; }
        if (getClass() != obj.getClass()) { return false; }
        final MyObject other = (MyObject) obj;
        if (!Objects.equals(this.name, other.name)) { return false; }
        if (!Objects.equals(this.message, other.message)) { return false; }
        if (!Objects.equals(this.id, other.id)) { return false; }
        return Objects.equals(this.object, other.object);
    }

    @Override
    public String toString() {
        return "\nMyObject{" + "id=" + id + ", name=" + name + ", message=" + message + ", object=" + object + '}';
    }
}

class MySecondObject {
    private Integer id;
    private String name;
    private String message;

    public MySecondObject(Integer id, String name, String message) {
        this.id = id;
        this.name = name;
        this.message = message;
    }

    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 13 * hash + Objects.hashCode(this.id);
        hash = 13 * hash + Objects.hashCode(this.name);
        hash = 13 * hash + Objects.hashCode(this.message);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) { return true; }
        if (obj == null) { return false; }
        if (getClass() != obj.getClass()) { return false; }
        final MySecondObject other = (MySecondObject) obj;
        if (!Objects.equals(this.name, other.name)) { return false; }
        if (!Objects.equals(this.message, other.message)) { return false; }
        return Objects.equals(this.id, other.id);
    }

    @Override
    public String toString() {
        return "MySecondObject{" + "id=" + id + ", name=" + name + ", message=" + message + '}';
    }
}

class MyObjectUtil {
    private MyObjectUtil() { }

    public static List<?> getList() {
        List<MyObject> myObjectList = new ArrayList<>();
        final ThreadLocalRandom r = ThreadLocalRandom.current();
        for (int i = 0; i < 1_000_000; i++) {
            myObjectList.add(new MyObject(r.nextInt(), "Name " + i, "Message " + i, new MySecondObject(r.nextInt(), "Second Object " + i, "Message " + i)));
        }
        myObjectList.add(new MyObject(r.nextInt(), "Name " + 0, "Message " + 0, null));
        myObjectList.sort((a, b) -> a.getId().equals(b.getId()) ? 0 : a.getId() > b.getId() ? 1 : -1);
        return Collections.unmodifiableList(myObjectList);
        //return myObjectList;
    }
}

public class MyObjectListTest {
    public static void main(String[] args) {
        List<MyObject> myObjectList = (List<MyObject>) MyObjectUtil.getList();
        long begin = System.currentTimeMillis();
        List<Integer> idList = new ArrayList<>();
        if (myObjectList != null) {
            for (MyObject object : myObjectList) {
                if (object != null && object.getObject() != null) {
                    idList
                }
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者ouribeb930

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:52:28