2016-07-08 7 views
1

In Anbetracht der folgenden Klasse zu holen:Java 8: Welches ist der bessere Weg ist, ein Objekt basierend auf Attributen in einer Sammlung

@Setter 
@Getter 
@EqualsAndHashCode(exclude = "text") 
@ToString 
public class Foo { 
    private Long xKey; 
    private Long yKey; 
    private String text 
} 

Wenn ich List<Foo> fooList und ich habe in dieser haben Listenelemente holen, wo:

{xKey, yKey} combination is in Map<Long,Long> combination = {{10L,20L},{11L,35L},{4L,1L}}

1 st Weise ist für jede Iteration durch und unter Verwendung von .get() Methode:

for(Entry<Long,Long> entry: combination.entrySet()){ 
    Foo tempFoo = new Foo(entry.getKey(),entry.getValue(),null); 
    Foo actualFoo = fooList.get(tempFoo); 
    System.out.println(actualFoo); 
} 

2. Weg ist durch Java-8-Streams

combination.foreach((k,v) -> { 
    Foo actualFoo = fooList.stream() 
      .filter(f -> f.getXKey.equals(k) && f.getYKey.equals(v)) 
      .findFirst() 
      .orElse(null); 
    System.out.println(actualFoo); 
}) 

Welche ist besser in der Leistung und Codierung der Praxis?

EDIT: Nachdem in Kommentaren suchen erkannte, dass ein Fehler, da in der ersten Code-Schnipsel ist statt fooList.get(tempFoo); es fooList.get(fooList.indexOf(tempFoo)); gewesen

+1

Eine 'Liste ' hat keine Methode 'get (Foo)'. – Holger

+0

hinzugefügt bearbeiten Kommentar – harvey123

Antwort

2

Zunächst einmal ein List<Foo> keine get(Foo) hat so offensichtlich, dass dies nur eine Beschreibung für so etwas wie list.get(list.indexOf(foo)) die eigentliche Instanz für Ihre Vorlage zu erhalten Dies bedeutet eine lineare Suche wie bei Ihrer Stream-Variante.

In dieser Hinsicht beide ein abgeraten, da sie eine lineare Iteration über ein Map, die Durchführung eines weitere verschachtelte lineare Suche auf der Liste, während ein Map typischerweise eine Lookup-Operation besser ist als eine lineare Suche bedeuten.

So sollen Sie über die Liste durchlaufen und einen Nachschlag auf die Map stattdessen durchführen:

for(Foo foo: fooList) { 
    if(foo.getYKey().equals(combination.get(foo.getXKey()))) { 
     System.out.println(foo); 
    } 
} 

den einzigen Unterschied ist, dass die Elemente in den Map ‚s bestellen, erscheinen nicht die Karte im Fall hat eine definierte Reihenfolge (HashMap hat nicht) und dass es nicht null s für Mappings drucken, die keine entsprechende Foo in der Liste haben.

Natürlich können Sie auch als forEach Betrieb schreiben:

fooList.forEach(foo -> { 
    if(foo.getYKey().equals(combination.get(foo.getXKey()))) { 
     System.out.println(foo); 
    } 
}); 

oder Stream-Betrieb

fooList.stream() 
     .filter(foo -> foo.getYKey().equals(combination.get(foo.getXKey()))) 
     .forEach(System.out::println); 

die alle gleichwertig sind.

Was Sie sollten nicht tun, ist eine intrinsische Sammlung API-Lookup-Operation wie Map.get mit einem Stream-Suchvorgang zu ersetzen.

+0

Vielen Dank für die detaillierte Antwort, ich habe hinzufügen Kommentar zu dem Fehler in der ersten Code-Schnipsel – harvey123

+0

Erweiterung dieser Frage, wenn die Kombination alle drei Felder enthält {xKey, yKey, Text} und diese sind in der Liste des Objekts ähnlich wie foo . Was wäre der beste Weg, um nach ihnen zu suchen – harvey123

0

Die zweite Lösung lesbar ist viel mehr haben sollte. Der erste wird nicht funktionieren, da der erwartete Parameter für die get-in-Liste ein int ist, der ein Index für die Liste ist. Schleifen- und Aggregatoperationen haben im Wesentlichen die gleiche Komplexität, so dass es keinen wirklichen Leistungsunterschied gibt, außer vielleicht, dass die erste Lösung etwas schlechter ist, weil sie diese temporären Foo-Objekte erzeugt.

1

Sie behandeln die Liste als eine Menge, also würde ich vorschlagen, die Implementierung entsprechend zu ändern. Wenn Sie es als Set verwenden, haben Sie eine weitaus bessere Leistung, zum Beispiel bei der Verwendung von HashSet als Implementierung. In diesem Fall würde ich auch stark davon abraten, die neue Set-Implementierung zu streamen, da eine einfache Suche schneller funktioniert als ein Index.

+0

Ich wollte die Reihenfolge beibehalten, so dass LinkedHashSet ich denke, – harvey123

+0

Sie können auch in TreeSet suchen, wie es die Sortierung beim Hinzufügen von Elementen erzwingt. Nicht besser, nur anders. – YoYo

3

Sie haben es viel kürzer:

fooList.stream() 
    .filter(f -> Objects.equals(f.getYKey(), combination.get(f.getXKey()))) 
    .forEach(System.out::println); 
+1

Ich sollte die Seite neu geladen haben, bevor ich eine Antwort geschrieben habe. Allerdings behalte ich meine Antwort, da sie die anderen Unterschiede zwischen den OP-Varianten und dieser Lösung betont. – Holger

Verwandte Themen