[JAVA] Verschiedene verwirrende Geschichten mit Map # computeIfAbsent

Map # computeIfAbsent ist eine in Java8 hinzugefügte Methode, und obwohl es 5 Jahre her ist, wusste ich es vor ungefähr einem Jahr.

V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)

Wenn der dem Schlüssel entsprechende Wert nicht vorhanden ist, wird MappingFunction aufgerufen und der Rückgabewert in Map gespeichert und zurückgegeben.

ConcurrentHashMap Bei der Implementierung des Prozesses zum Zwischenspeichern von Daten auf einem Websystem stellten sich Fragen.

private Map<String, String> cache = new ConcurrentHashMap<>()

public String get(String id) {
  return cache.computeIfAbsent(key, key -> {
    if (/*Eine dem Schlüssel entsprechende externe Datei ist vorhanden*/) {
      //Lesen Sie die Datei und geben Sie sie zurück
      return readData;
    }
    //Es gibt keine entsprechende Datei
    return null;
  });
}

Ist es in Ordnung, null zurückzugeben, obwohl ConcurrentHashMap den Wert nicht null enthalten kann? Also habe ich versucht, mit dem Testcode zu experimentieren.

Map<String, String> map = new ConcurrentHashMap<>();
String ret = map.computeIfAbsent("test", key -> null);
System.out.println(ret);

Das Ausführungsergebnis war keine Ausnahme und der Rückgabewert war null. Dies ist in Javadoc Es wurde richtig geschrieben. .. ..

Wenn der angegebene Schlüssel noch keinem Wert zugeordnet ist, versuchen Sie, diesen Wert mit der angegebenen Zuordnungsfunktion und zu berechnen
Wenn es nicht null ist, geben Sie es in diese Karte ein.

Kotlin Wie Sie sehen können, ist das Obige in Java geschrieben, aber da sich die Systementwicklung ebenfalls in einem frühen Stadium befindet, ist beim Umschreiben des Codes in Kotlin ein Kompilierungsfehler aufgetreten. Die Version von Kotlin ist 1.3.31.

val cache = ConcurrentHashMap<String, String>()

fun get(id: String): String? {
  return cache.computeIfAbsent(id) {
    if (/*Eine dem Schlüssel entsprechende externe Datei ist vorhanden*/) {
      //Lesen Sie die Datei und geben Sie sie zurück
      return readData;
    }
    return null; //Error! Kotlin: Null can not be a value of a non-null type String
  }
}

Laut Kotlins API-Referenz Map.get

operator fun get(key: K): V?

Und V erlaubt null, aber der Rückgabewert von MappingFunction scheint V zu bleiben. Als Workaround

val ret: String? = map.computeIfAbsent("test") { null!! }

Wenn Sie !! wie folgt hinzufügen, wird der Kompilierungsfehler behoben, aber kotlin.KotlinNullPointerException tritt zur Laufzeit auf. .. .. orz

Als Lösung

val map = ConcurrentHashMap<String, String?>()
val ret: String? = map.computeIfAbsent("test") { null }

Ich wusste nur von Anfang an, dass ich V mit Nulltoleranz deklariere. Wenn ich mir jedoch Sorgen machte, dass der Rückgabewert von get ein seltsamer Typ sein könnte, gab es keine Selbstverständlichkeit, und ich habe bisher keine Unannehmlichkeiten festgestellt, indem ich String gemacht habe. Ist dies also die richtige Antwort? Aha.

Recommended Posts

Verschiedene verwirrende Geschichten mit Map # computeIfAbsent