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
filterormap) adds small overhead. Combine multiple predicates into one filter, or skip unnecessary mappings, to reduce this cost. For example, a singlefilter(object -> object != null && object.getObject() != null)is better than chaining two separatefiltercalls. - Leverage primitive streams: Your test collects
IntegerIDs—usingIntStream(viamapToInt) instead ofStream<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()onIntStreaminstead ofCollectors.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 likeCollectors.toCollection(ArrayList::new)to avoid unnecessary type checks or intermediate allocations. For primitive values, collectors likeCollectors.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
相关产品推荐
相关产品推荐

