Konvertieren von Array zu HashMap mit Java 8 Stream

8

Ich schreibe eine Funktion, um Array mit Java 8 Stream in Map zu konvertieren.

Hier ist was ich wollte

%Vor%

Gültige Verwendungen

%Vor%

Ungültige Gebräuche

%Vor%

Irgendwelche hilft?

Danke!

    
Loc 30.01.2017, 22:12
quelle

4 Antworten

6

Sie können

verwenden %Vor%

aber es wird Ihnen eine (funded) unchecked Warnung geben. Ihre Methode kann nicht das Versprechen halten, eine korrekt eingegebene Map<K, V> für ein Array von beliebigen Objekten zurückzugeben, und noch schlimmer, sie wird nicht mit einer Ausnahme fehlschlagen, aber eine uneinheitliche Map automatisch zurückgeben, wenn Sie Objekte vom falschen Typ übergeben .

Eine sauberere, häufig verwendete Lösung ist

%Vor%

Dies kann ohne Warnung kompiliert werden, da die Korrektheit zur Laufzeit überprüft wird. Der Aufrufcode muss angepasst werden:

%Vor%

Neben der Notwendigkeit, die tatsächlichen Typen als Klassenliterale anzugeben, hat sie den Nachteil, dass sie generische Schlüssel- oder Werttypen nicht unterstützt (da sie nicht als Class ausgedrückt werden können) und nur noch keine Kompilierungszeitsicherheit haben eine Laufzeitprüfung.

Es lohnt sich Java 9 anzusehen . Dort können Sie Folgendes tun:

%Vor%

Dadurch wird eine unveränderliche Karte eines nicht angegebenen Typs anstelle von HashMap erstellt, aber der interessante Punkt ist die API.

Es gibt eine Methode <K,V> Map.Entry<K,V> entry(K k, V v) , die mit
<K,V> Map<K,V> ofEntries(Map.Entry<? extends K,? extends V>... entries) kombiniert werden kann, um eine Karte variabler Länge zu erstellen (varargs sind jedoch immer noch auf 255 Parameter beschränkt).

Sie können eine ähnliche Sache implementieren:

%Vor%

Die Convenience-Methode (n) of werden auf die einzige Weise implementiert, dies kann mit type safety erfolgen: als überladene Methoden mit unterschiedlicher Anzahl von Argumenten, wie

%Vor%

(Java 9 macht den Schnitt bei zehn Mappings, wenn Sie mehr haben, müssen Sie die ofEntries(entry(k1, v1), …) Variante verwenden).

Wenn Sie diesem Muster folgen, sollten Sie Ihren toMap name beibehalten oder nur map verwenden, anstatt " of " aufzurufen, da Sie nicht die Map -Schnittstelle schreiben.

Diese Überladungen sehen vielleicht nicht sehr elegant aus, aber sie lösen alle Probleme. Sie können den Code genau wie in Ihrer Frage schreiben, ohne Class objects anzugeben, aber die Art der Kompilierungszeit Typsicherheit und sogar die Ablehnung von Versuchen, sie mit einer ungeraden Anzahl von Argumenten aufzurufen, zu erhalten.

Sie müssen bei einer bestimmten Anzahl von Parametern einen Schnitt vornehmen, aber wie bereits erwähnt, unterstützen selbst Varargs keine unbegrenzten Parameter. Und das ofEntries(entry(…), …) Formular ist nicht so schlecht für größere Karten.

Der Kollektor Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue) gibt einen unspezifizierten Kartentyp zurück, der möglicherweise sogar unveränderbar ist (obwohl es in der aktuellen Version ein HashMap ist). Wenn Sie sicherstellen möchten, dass eine HashMap Instanz zurückgegeben wird, müssen Sie stattdessen Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1,v2)->{throw new IllegalArgumentException("duplicate key");}, HashMap::new) verwenden.

    
Holger 31.01.2017, 11:28
quelle
2

Genau das zu erreichen, was Sie wollen, funktioniert wahrscheinlich nicht für Karten, deren Schlüsseltyp sich von ihrem Werttyp unterscheidet. Dies liegt daran, dass die variable Arity-Deklaration von Java ( Object... entries part) nur einen Typ unterstützt.

Einige Optionen kommen mir in den Sinn:

  1. Sie könnten die Überprüfungen dynamisch durchführen und eine unzulässige Argumentausnahme auslösen, wenn die Werte nicht übereinstimmen. Aber Sie werden den Compiler-Typ-Check verlieren.

  2. Sie könnten eine Pair -Klasse definieren und ein wenig mit statischem Import spielen, um fast das zu erreichen, was Sie wollen:

z. B .:

%Vor%     
Michael Bar-Sinai 30.01.2017 22:40
quelle
1

Hier ist meine Idee von JDK 8 stream:

%Vor%

Wenn Sie die Drittanbieterbibliothek AbacusUtil nicht stören, könnte der Code folgendermaßen vereinfacht werden:

%Vor%

Und ich denke, der effizienteste Weg ist eine for-Schleife, wenn Sie die Stream-API nicht besonders verfolgen

%Vor%     
user_3380739 30.01.2017 22:38
quelle
0

Sie können etwas wie Kartenliterale verwenden.
Um dies zu erreichen, können Sie eine Factory-Methode verwenden:

%Vor%

Schließlich können Sie Folgendes tun:

%Vor%

Ausgabe:

  

{a = 1, b = 2, c = 3}

Ich hoffe, dass dir das den richtigen Weg gibt.

    
nazar_art 30.01.2017 22:44
quelle