2016-10-27 5 views
1

Es gibt mehrere Möglichkeiten, ein Element in einer Liste zu finden. Zum Beispiel habe ich eine Liste mit einigen Elementen, die eine eindeutige ID haben. Für eine gegebene ID möchte ich das spezifische Element aus der Liste zurückgeben.Welcher Code ist besser, um ein bestimmtes Element in einer Liste zu finden

Liste Beispiel (nur Schema, nicht die korrekte Syntax):

//Element(String id, int value) 
List<Element> list = new ArrayList(); 
int elemCount = 1000000; 
for(int i = 0; i<elemCount; i++) 
    list.add(new Element("id"+i, i)); 
Collections.shuffle(list); 
Element e = getElement("id" + ThreadLocalRandom.current().nextInt(0, elemCount)); 

die folgenden zwei Verfahren gegeben, die besser nicht durchführt im Allgemeinen auf der Grundlage der Java-interne Implementierung und warum?

Erste Methode:

public Element getElement(String id) { 
    return list.stream() 
     .filter(e -> e.getId().equals(id)) 
     .findAny() 
     .orElse(null); 
} 

Zweite Methode:

public Element getElement(String id) { 
    for(Element e : list) 
     if(e.getId().equals(id)) 
     return e; 
    return null; 
} 
  • "Element" als Objekt wird nur beispielsweise gewählt.
  • Nicht relevant: Struktur und Größe des Elements, die PC-Leistung usw.
  • Java Version: 1.8.0_111
+0

Die erste, die mit Ihren Daten auf Ihrem Computer abgeschlossen wird, führt zu besseren Ergebnissen. Also versuche es herauszufinden. –

+0

@MarkoTopolnik Wie Sie in den Beispielen sehen können, handelt es sich nicht um spezifische Daten. Alle Daten sollten dasselbe ausführen. Daher hoffe ich, eine allgemeine und gut erklärte Antwort zwei meiner Frage zu finden. – Spen

+0

Was ist, wenn es auf Datengröße, Ihre JVM-Version, Ihre Anzahl von Kernen usw. ankommt? Sie haben die gleiche Groß-O-Komplexität, der Rest liegt an Details, die Sie nicht vorgeben können, existieren nicht. –

Antwort

0

Da ich keine Antwort auf der Grundlage der Java-interne Implementierung bekommen konnte, Ich habe einen Benchmark für mich selbst gemacht.

Ich möchte mit Ihnen die Ergebnisse teilen, die ich kam. Ich habe einen Benchmark für jede Liste von Größe 1 bis 1000 durchgeführt. Jeder Benchmark für jede Listengröße lief 10000 mal mit dem Durchschnitt, der berechnet wurde, um Fehler zu vermeiden.

Haftungsausschluss: Ich bin kein Benchmark-Experte und habe einfach eine einfache Implementierung durchgeführt. Die Ergebnisse sind nicht 100% genau und die Schlussfolgerungen, die ich gemacht habe, können falsch sein. Wenn Sie es besser können, dann fühlen Sie sich frei, verbessern Sie meinen Benchmark oder machen Sie sich selbst und veröffentlichen Sie die Ergebnisse in einer neuen Antwort.

Sie können die Benchmark-Dateien finden Sie hier: https://github.com/Spenhouet/BenchmarkFindElement

  1. eine parallelStream für diese einfache Aufgabe Verwendung hat mehr Aufwand und ist langsamer als nur ein normaler Strom.
  2. Wenn die Liste sortiert ist und das gewünschte Element das letzte Element der Liste ist, ist .findFirst() schneller als .findAny().
  3. Wenn die Liste sortiert ist und das gewünschte Element das letzte der Liste ist, mit .findAny() ist die "for" -Methode schneller.
  4. Wenn die Liste gemischt ist und die gewünschte Artikel-ID zufällig ist, macht .findFirst() und .findAny() keinen Unterschied.
  5. Wenn die Liste gemischt wird und die gewünschte Artikel-ID zufällig ist, gibt es nur einen kleinen Unterschied zwischen der "Stream" - und der "for" -Methode. Die „Strom“ Methode ist ein wenig besser

mit Java Version getestet: 1.8.0_111

Zum Beispiel für das Kennfeld einer zufällige ID in dem die neu gemischten Listen mit 505-575 Artikeln zu finden.Die blaue Linie ist die "for" -Methode und die rote Linie die "stream" -Methode.

Benchmark-Graph for subset of items

Zum Beispiel das Leistungsdiagramm für eine zufällige ID in der die gemischten Listen mit 1-100000 Artikel zu finden (nur 10-mal Durchschnitt). Die blaue Linie ist die "for" -Methode und die rote Linie die "stream" -Methode.

Benchmark-Graph for 1 to 100000 items

Wenn Sie einen Blick auf einige Graphen nehmen wollen/generieren sie Ihr selfe, dann laden Sie sich einfach das Repository von der Github Link oben, um das Projekt importieren und mit den VM-Optionen laufen -Xms1024m -Xmx4068m .

Mit 1-40.000 Listenelemente und 100 läuft jeweils für mittlere und die VM-Optionen: -Xms1024m -Xmx4068m -XX: + PrintCompilation -verbose: gc -Xbatch -XX: CICompilerCount = 2

Benchmark-Graph for 1 to 40000 items and other VM options

+1

Die Benchmark ist auf mehrere Arten fehlerhaft. Das Ergebnis * kann * noch bestätigt werden, wenn ein [richtiges Microbenchmark] (http: // stackoverflow.com/questions/504103/how-do-ich-schreibe-a-correct-micro-benchmark-in-java), möchte ich nur darauf hinweisen, dass Sie aus den aktuellen Ergebnissen keine tiefgreifenden Schlussfolgerungen ziehen können. – Marco13

+0

Für sequentielle Stream 'findFirst' und' findAny' interne Implementierung ist genau das gleiche, so Ihre Schlussfolgerung # 2 ist definitiv falsch. Beim parallelen Strom kann das Ergebnis stark von der Anzahl der Kerne und der Position des Zielelements abhängen (in einigen Kombinationen würden weniger Kerne ein schnelleres Ergebnis liefern). –

+0

@ Marco13 Vielen Dank, dass Sie darauf hingewiesen haben. Ich bin kein Experte im Benchmarking und habe keine Zeit, es fortgeschrittener zu machen. Für mich sind die Ergebnisse, die ich bekommen habe, ausreichend, aber gut, um für andere zu wissen, dass sie nicht völlig genau sind. – Spen

Verwandte Themen