Gibt es eine kurze und süße Möglichkeit, ein List<Integer>
oder vielleicht ein Integer[]
oder int[]
mit sequentiellen Werten von einem start
Wert zu einem end
Wert zu generieren ?
Das heißt, etwas kürzer als, aber gleich 1 der folgenden:
void List<Integer> makeSequence(int begin, int end) {
List<Integer> ret = new ArrayList<>(end - begin + 1);
for (int i=begin; i<=end; i++) {
ret.add(i);
}
return ret;
}
Die Verwendung von Guave ist in Ordnung.
Aktualisieren:
Performance-Analyse
Da diese Frage mehrere gute Antworten erhalten hat, sowohl mit nativem Java 8 als auch mit Bibliotheken von Drittanbietern, dachte ich, ich würde die Leistung aller Lösungen testen.
Der erste Test testet einfach das Erstellen einer Liste von 10 Elementen [1..10]
mit den folgenden Methoden:
- classicArrayList : Der oben in meiner Frage angegebene Code (und im Wesentlichen der gleiche wie die Antwort von adarshr).
- eclipseCollections : Der in Donalds Antwort unten angegebene Code unter Verwendung von Eclipse Collections 8.0.
- guavaRange : Der Code, der in der Antwort von daveb unten angegeben ist. Technisch gesehen erzeugt dies kein,
List<Integer>
sondern einContiguousSet<Integer>
- aber da esIterable<Integer>
in der richtigen Reihenfolge implementiert wird, funktioniert es hauptsächlich für meine Zwecke. - intStreamRange : Der Code in der folgenden Antwort von Vladimir , der verwendet
IntStream.rangeClosed()
- der in Java 8 eingeführt wurde. - streamIterate : Der in der folgenden Antwort von Catalin angegebene Code, der auch die
IntStream
in Java 8 eingeführten Funktionen verwendet .
Hier sind die Ergebnisse in Kilobetrieben pro Sekunde (höhere Zahlen sind besser) für alle oben genannten mit Listen der Größe 10:
... und noch einmal für Listen der Größe 10.000:
Das letzte Diagramm ist korrekt - andere Lösungen als Eclipse und Guava sind zu langsam, um überhaupt einen einzelnen Pixelbalken zu erhalten! Die schnellen Lösungen sind 10.000 bis 20.000 Mal schneller als die anderen.
Was hier natürlich vor sich geht, ist, dass die Guaven- und Eclipse-Lösungen tatsächlich keine 10.000-Elemente-Liste materialisieren - sie sind einfach Wrapper fester Größe um den Start- und Endpunkt. Jedes Element wird nach Bedarf während der Iteration erstellt. Da wir in diesem Test nicht wirklich iterieren, werden die Kosten zurückgestellt. Alle anderen Lösungen materialisieren tatsächlich die vollständige Liste im Speicher und zahlen einen hohen Preis für einen Benchmark nur für die Erstellung.
Lassen Sie uns etwas Realistischeres tun und auch alle ganzen Zahlen durchlaufen und summieren. Bei der IntStream.rangeClosed
Variante sieht der Benchmark also so aus:
@Benchmark
public int intStreamRange() {
List<Integer> ret = IntStream.rangeClosed(begin, end).boxed().collect(Collectors.toList());
int total = 0;
for (int i : ret) {
total += i;
}
return total;
}
Hier ändern sich die Bilder stark, obwohl die nicht materialisierenden Lösungen immer noch die schnellsten sind. Hier ist Länge = 10:
... und Länge = 10.000:
Die lange Iteration über viele Elemente gleicht die Dinge viel aus, aber Eclipse und Guave bleiben selbst beim 10.000-Elemente-Test mehr als doppelt so schnell.
Wenn Sie also wirklich eine List<Integer>
Eclipse-Sammlung wünschen , scheint dies die beste Wahl zu sein. Wenn Sie Streams jedoch nativer verwenden (z. B. .boxed()
die primitive Domäne vergessen und reduzieren), werden Sie wahrscheinlich schneller als alle diese sein Varianten.
1 Möglicherweise mit Ausnahme der Fehlerbehandlung, z. B. wenn end
< begin
oder wenn die Größe einige Implementierungs- oder JVM-Grenzwerte überschreitet (z. B. Arrays größer als 2^31-1
.