it-swarm.com.de

ConcurrentHashMap JDK 8, wann computeIfPresent verwendet werden soll

Die neue Version von Concurrent Hash Map von jdk 8 hat zwei neue Methoden.

computeIfAbsent

computeIfPresent  

putIfAbsent - Alte Methode

Ich verstehe die Anwendungsfälle von putIfAbsent und computeIfAbsent ..__ Aber ich bin mir nicht sicher, in welchen Szenarien ich computeIfPresent ..__ benutze computeIfPresent jetzt haben .putIfAbsent Erstellen Sie mindestens eine zusätzliche Instanz des Werts.

Ist der Grund nur die Abwärtskompatibilität?

15
veritas

Wie in der anderen Antwort erwähnt: Methoden werden aus Gründen der Abwärtskompatibilität immer beibehalten, auch wenn neue, leistungsfähigere Methoden eingeführt werden.

Zum Anwendungsfall für computeIfPresent: Es kann schwierig sein, ein Beispiel zu finden, das klein genug ist, um nicht durchdacht zu wirken und dennoch überzeugend zu sein. Im Allgemeinen beabsichtigt diese Methode, einen vorhandenen Wert in beliebiger Form update zu definieren. 

Ein Beispiel könnte eine (eingeschränkte) Wortanzahl sein: Für eine gegebene Menge von Wörtern speichert man eine Anfangszählung von 0 in der Karte. Dann wird eine Folge von Wörtern verarbeitet: Immer wenn ein Wort aus dem ursprünglichen Satz gefunden wird, wird seine Anzahl um 1 erhöht: 

import Java.util.LinkedHashMap;
import Java.util.Map;

public class ComputeIfPresentExample 
{
    public static void main(String[] args) 
    {
        Map<String, Integer> wordCounts = new LinkedHashMap<String, Integer>();

        String s = 
            "Lorem ipsum dolor sit amet consetetur iam nonumy sadipscing " + 
            "elitr, sed diam nonumy eirmod tempor invidunt ut erat sed " + 
            "labore et dolore magna dolor sit amet aliquyam erat sed diam";

        wordCounts.put("sed", 0);
        wordCounts.put("erat", 0);

        for (String t : s.split(" "))
        {
            wordCounts.computeIfPresent(t, (k,v) -> v+1);
        }
        System.out.println(wordCounts);
    }
}

(Dinge wie diese können natürlich anders gelöst werden, aber dies ist in der einen oder anderen Form eine ziemlich häufige Aufgabe, und die neue Methode ermöglicht eine recht prägnante und elegante Lösung.)

30
Marco13

Ein häufiger Anwendungsfall sind maps mit Collections , wie

Map<String, Collection<String>> strings = new HashMap<>();

computeIfAbsent und computeIfPresent sind sehr praktische Vorgänge zum Hinzufügen und Entfernen von Elementen zur/aus der Sammlung. Hier ein Beispiel, in dem die Zeichenfolgen nach ihrem ersten Zeichen gruppiert werden. Beachten Sie, dass sowohl die Schlüssel als auch die Sammlungen bei Bedarf erstellt und bereinigt werden, wenn die Sammlung leer wird:

void addString(String a) {
    String index = a.substring(0, 1);
    strings.computeIfAbsent(index, ign -> new HashSet<>()).add(a);
}

void removeString(String a) {
    String index = a.substring(0, 1);
    strings.computeIfPresent(index, (k, c) -> {
        c.remove(a);
        return c.isEmpty() ? null : c;
    });
}

Dies ist in Multithreading-Umgebungen extrem leistungsfähig, da ConcurrentMaps diese Vorgänge atomar ausführt.

Beispiel:

                         // {}
addString("a1");         // {a=[a1]}      <-- collection dynamically created
addString("a2");         // {a=[a1, a2]}
removeString("a1");      // {a=[a2]}
removeString("a2");      // {}            <-- both key and collection removed

Etwas extra zucker:

void addString(String a) {
    String index = a.substring(0, 1);
    strings.computeIfAbsent(index, ign -> new HashSet<>()).add(a);
}

void removeString(String a) {
    String index = a.substring(0, 1);
    strings.computeIfPresent(index, (i, c) -> c.remove(a) && c.isEmpty() ? null : c);
}
3
steffen

Ich habe computeIfPresent als nullsichere Methode zum Abrufen von Kleinbuchstaben aus einer Map von Zeichenfolgen verwendet.

String s = fields.computeIfPresent("foo", (k,v) -> v.toLowerCase())

Bevor computeIfPresent verfügbar war, muss ich Folgendes tun:

String s = map.get("foo");
if (s != null) {
    s = s.toLowerCase();
}

Oder dieses:

String s = map.containsKey("foo") ? map.get("foo").toLowerCase() : null;
0
austin327

Das JDK unterbricht kaum die Rückwärtskompatibilität. Denn dann können Sie nicht einfach Software von einer älteren Version mit der neuesten Version portieren oder ausführen. 

Sie können Software, die mit einer älteren Version der Bibliothek kompiliert wurde, mit einer beliebigen Version ausführen (dh Benutzer, auf denen JRE installiert ist), auf denen diese Funktionen noch vorhanden sind.

0
Thirler