IDEA suggerisce di sostituire, per esempio, questo:IntelliJ IDEA suggerisce di sostituire i loop con il metodo foreach. Dovrei farlo sempre quando possibile?
for (Point2D vertex : graph.vertexSet()) {
union.addVertex(vertex);
}
con questo:
graph.vertexSet().forEach(union::addVertex);
Questa nuova versione è sicuramente molto più leggibile. Ma ci sono situazioni in cui è meglio attenersi al buon costrutto del vecchio linguaggio per le reti iterative piuttosto che usare il nuovo metodo foreach
?
Ad esempio, se ho capito bene, il meccanismo di riferimento del metodo implica la costruzione di un oggetto anonimo Consumer
che altrimenti (con il costrutto del linguaggio for
) non sarebbe stato costruito. Potrebbe diventare un collo di bottiglia per le prestazioni di alcune azioni?
Così ho scritto questo benchmark non molto esaustivo:
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;
}
}
e ottenuto:
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
Come viene foreach
è più efficiente in entrambi i casi: quando faccio praticamente nulla e quando lo faccio un po ' lavoro vero? Non foreach
semplicemente incapsulare Iterator
? Questo benchmark è corretto? Se lo è, c'è qualche ragione oggi per usare il costrutto vecchio linguaggio con Java 8?
Domande correlate: http://stackoverflow.com/q/23265855/1441122 e http://stackoverflow.com/q/16635398/1441122 –
i microbenchmark sono altrettanto accurati e utili quanto i loro esperti nella creazione di essi. i microbenchmark di solito giocano direttamente all'effetto Dunning-Kruger con i risultati attesi. –
@JarrodRoberson Ma questo utilizza JMH, che ha un approccio consolidato e strumenti per il benchamrking. Non c'è niente in questo benchmark che deriva dalla mia esperienza e non dal manuale a JMH. – gvlasov