it-swarm.com.de

Java 8-Stream-Map für den Eintragssatz

Ich versuche, eine Kartenoperation für jeden Eintrag in einem Map-Objekt durchzuführen.

Ich muss ein Präfix vom Schlüssel nehmen und den Wert von einem Typ in einen anderen konvertieren. Mein Code übernimmt Konfigurationseinträge von einem Map<String, String> und konvertiert in einen Map<String, AttributeType> (AttributeType ist nur eine Klasse, die Informationen enthält. Weitere Erklärungen sind für diese Frage nicht relevant.)

Das Beste, was ich mit Java 8 Streams erreichen konnte, ist folgendes:

private Map<String, AttributeType> mapConfig(Map<String, String> input, String prefix) {
   int subLength = prefix.length();
   return input.entrySet().stream().flatMap((Map.Entry<String, Object> e) -> {
      HashMap<String, AttributeType> r = new HashMap<>();
      r.put(e.getKey().substring(subLength), AttributeType.GetByName(e.getValue()));
      return r.entrySet().stream();
   }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}

Da es nicht möglich ist, einen Map.Entry zu erstellen, da es sich um eine Schnittstelle handelt, wird der einzelne Eintrag Map erstellt und flatMap() verwendet, was hässlich erscheint.

Gibt es eine bessere Alternative? Es scheint schöner, dies mit einer for-Schleife zu tun:

private Map<String, AttributeType> mapConfig(Map<String, String> input, String prefix) {
   Map<String, AttributeType> result = new HashMap<>(); 
   int subLength = prefix.length(); 
   for(Map.Entry<String, String> entry : input.entrySet()) {
      result.put(entry.getKey().substring(subLength), AttributeType.GetByName( entry.getValue()));
   }
   return result;
}

Sollte ich die Stream-API dafür vermeiden? Oder gibt es einen schöneren Weg, den ich vermisst habe?

29
Wil Selwood

Einfach den "alten for-Loop-Weg" in Streams übersetzen:

private Map<String, String> mapConfig(Map<String, Integer> input, String prefix) {
    return input.entrySet().stream()
            .collect(Collectors.toMap(
                   entry -> entry.getKey().substring(subLength), 
                   entry -> AttributeType.GetByName(entry.getValue())));
}
69
Smutje

Die Frage ist vielleicht etwas veraltet, aber Sie können AbstractMap.SimpleEntry <> wie folgt verwenden:

private Map<String, AttributeType> mapConfig(
    Map<String, String> input, String prefix) {
       int subLength = prefix.length();
       return input.entrySet()
          .stream()
          .map(e -> new AbstractMap.SimpleEntry<>(
               e.getKey().substring(subLength),
               AttributeType.GetByName(e.getValue()))
          .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

jedes andere Pair-like-Value-Objekt würde ebenfalls funktionieren (dh ApacheCommons Pair Tuple).

14
Dawid Pancerz

Bitte machen Sie den folgenden Teil der Collectors-API:

<K, V> Collector<? super Map.Entry<K, V>, ?, Map<K, V>> toMap() {
  return Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue);
}
5

Hier ist eine kürzere Lösung von AbacusUtil

Stream.of(input).toMap(e -> e.getKey().substring(subLength), 
                       e -> AttributeType.GetByName(e.getValue()));
0
user_3380739