IDEA gợi ý để thay thế, ví dụ, điều này:IntelliJ IDEA đề xuất thay thế cho các vòng lặp bằng phương pháp foreach. Tôi có nên luôn làm điều đó khi có thể không?
for (Point2D vertex : graph.vertexSet()) {
union.addVertex(vertex);
}
với điều này:
graph.vertexSet().forEach(union::addVertex);
Phiên bản mới này chắc chắn nhiều hơn nữa có thể đọc được. Nhưng có những tình huống nào khi tôi nên gắn bó với cấu trúc ngôn ngữ cũ tốt cho các iteratables thay vì sử dụng phương thức foreach
mới? Ví dụ, nếu tôi hiểu chính xác, cơ chế tham chiếu phương thức ngụ ý việc xây dựng một đối tượng vô danh Consumer
nếu không (với cấu trúc ngôn ngữ for
) sẽ không được xây dựng. Điều đó có thể trở thành một nút cổ chai hiệu suất đối với một số hành động không?
Vì vậy, tôi đã viết chuẩn không phải là rất đầy đủ này:
package org.sample;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.infra.Blackhole;
import org.tendiwa.geometry.Point2D;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class LanguageConstructVsForeach {
private static final int NUMBER_OF_POINTS = 10000;
private static final List<Point2D> points = IntStream
.range(0, NUMBER_OF_POINTS)
.mapToObj(i -> new Point2D(i, i * 2))
.collect(Collectors.toList());
@Benchmark
@Threads(1)
@Fork(3)
public void languageConstructToBlackhole(Blackhole bh) {
for (Point2D point : points) {
bh.consume(point);
}
}
@Benchmark
@Threads(1)
@Fork(3)
public void foreachToBlackhole(Blackhole bh) {
points.forEach(bh::consume);
}
@Benchmark
@Threads(1)
@Fork(3)
public List<Point2D> languageConstructToList(Blackhole bh) {
List<Point2D> list = new ArrayList<>(NUMBER_OF_POINTS);
for (Point2D point : points) {
list.add(point);
}
return list;
}
@Benchmark
@Threads(1)
@Fork(3)
public List<Point2D> foreachToList(Blackhole bh) {
List<Point2D> list = new ArrayList<>(NUMBER_OF_POINTS);
points.forEach(list::add);
return list;
}
}
Và có:
Benchmark Mode Samples Score Error Units
o.s.LanguageConstructVsForeach.foreachToBlackhole thrpt 60 33693.834 ± 894.138 ops/s
o.s.LanguageConstructVsForeach.foreachToList thrpt 60 7753.941 ± 239.081 ops/s
o.s.LanguageConstructVsForeach.languageConstructToBlackhole thrpt 60 16043.548 ± 644.432 ops/s
o.s.LanguageConstructVsForeach.languageConstructToList thrpt 60 6499.527 ± 202.589 ops/s
Làm thế nào đến foreach
là hiệu quả hơn trong cả hai trường hợp: khi tôi làm hầu như không có gì và khi tôi làm một số công việc thực tế? Không foreach
chỉ cần đóng gói Iterator
? Điểm chuẩn này có đúng không? Nếu có, hôm nay có lý do gì để sử dụng cấu trúc ngôn ngữ cũ với Java 8 không?
Các câu hỏi liên quan: http://stackoverflow.com/q/23265855/1441122 và http://stackoverflow.com/q/16635398/1441122 –
microbenchmarks chỉ chính xác và hữu ích như người sáng tạo của họ chuyên môn trong việc tạo ra chúng. microbenchmarks thường chơi trực tiếp với hiệu ứng Dunning-Kruger với kết quả mong đợi. –
@JarrodRoberson Nhưng cái này đang sử dụng JMH, trong đó có một cách tiếp cận tốt và các công cụ cho benchamrking. Không có gì trong tiêu chuẩn này đến từ chuyên môn của tôi và không phải từ hướng dẫn sử dụng cho JMH. – gvlasov