Ich möchte Optional für die Behandlung von Nullwerten verwenden. Der "knifflige" Teil, an den ich nicht denken kann, was der beste Weg ist, ist, dass ich die Protokollierung durchführen möchte, wenn der Wert Null ist. Ich kann das mit folgendem Code erreichen - aber es fühlt sich unangenehm an.

(Update: Ich habe meine eigene Antwort mit Optional von Java 9 veröffentlicht)

Nehmen wir an, der Code sieht folgendermaßen aus:

// logLine.getSomeProperty returns Optional<String>

List<LogDetails> logDetails = logLine.getSomeProperty()
    .map(this::extractLogDetails)
    .orElseGet(() -> logError(logLine));
List<LogDetails> extractLogDetails(String s) {
    List<LogDetails> logDetails = new ArrayList<>();
    String sp = "(?:([A-Z0-9]{5,7})-([A-Z0-9]{9})-(.{4}))"; 
    Pattern p = Pattern.compile(sp, Pattern.CASE_INSENSITIVE);
    Matcher m = p.matcher(s);
    while (m.find()) {
        logDetails.add(new LogDetails(m.group(1), m.group(2), m.group(3)));
    }
    return logDetails;
}
List<LogDetails> logError(LogLine logLine) {
    log.error("Error while ... {} ", logLine));
    persistence.setErrorStatus(logLine, FAILED_PARSING);
    return new ArrayList<>();
}

Es würde tun, was ich will, aber ich habe einige "Probleme" damit.

  • Ich fand es seltsam, dass diese Methode namens orElseGet für die Protokollierung verwendet wird Fehler.
  • Ich könnte orElseGet durch orElseThrow und logError ersetzen und dort nichts werfen - was mir auch nicht gefällt.
  • Die logError-Methode gibt eine Liste zurück, die ich nicht verwende, und es sieht seltsam aus, etwas von einer Methode zurückzugeben, die ungültig sein sollte.
  • Es muss einfach einen besseren Weg geben
  • Fälle, in denen someProperty nicht null ist, aber keine Übereinstimmungen vorliegen - ich würde auch gerne protokollieren, aber dafür würde ich eine weitere Codezeile benötigen, um zu überprüfen, ob logDetails.size() == 0
3
lapkritinis 20 Jän. 2019 im 03:56

3 Antworten

Beste Antwort

Das orElseGet ist nicht wirklich als Fehlerbehandlungsmechanismus gedacht, sondern als Möglichkeit, einen anderen Standardwert zu generieren, falls die Optional -Instanz keinen enthält.

Wenn Sie überprüfen möchten, ob Optional explizit leer ist, verwenden Sie einfach die Prüfung Optional.isPresent() und führen Sie in diesem Fall die logError() aus.

Was Sie zuerst denken müssen, ist, wenn das Optional leer ist, was möchten Sie tun? Möchten Sie neben der Protokollierung des Fehlers mit einer leeren Liste fortfahren?

Wenn ja, dann könnten Sie so etwas haben:

List<LogDetails> logDetails = logLine.getSomeProperty()
    .map(this::extractLogDetails)
    .orElseGet(Collections::emptyList);

Danach könnten Sie tun:

if (logDetails.isEmpty()) {
  logError(logline);
}

Wenn Sie alternativ überhaupt keine leere Liste haben möchten, können Sie die Dinge auf einer optionalen Ebene halten. Auf diese Weise werden beide Fälle, in denen getSomeProperty() leer ist oder in denen die generierte Liste leer ist, auf dieselbe Weise behandelt.

Optional<List<LogDetails>> logDetailsOpt = logLine.getSomeProperty() 
                       .map(this::extractLogDetails)
                       .filter(list -> !list.isEmpty());

if (!logDetailsOpt.isPresent()) {
  logError(logLine);
}

In beiden Fällen wird von logError() keine Rückgabe erwartet. Es tut, was es in seinem Namen tun soll, und protokolliert den Fehler.

Versuchen Sie, Ihre Absichten in Ihrem Code klar zu machen, anstatt zu versuchen, die Funktionalität von Optional zu überbeanspruchen. Die Lesbarkeit ist wertvoller.

2
jbx 20 Jän. 2019 im 01:19

Anstatt den Ergebnistyp zu ändern oder sich im Stream zu protokollieren, können Sie einfach partitionierte Map zurückgeben. Führen Sie dann nach Erhalt des Ergebnisses die Protokollfunktion auf der resultierenden Karte entsprechend aus.

 Map<Boolean, List<String>> map = Stream.of("a", "aaa", "aaaa")
           ----
                .collect(() -> Collectors.partitioningBy(predicate))
           ----
1
WMG 20 Jän. 2019 im 01:45

Ich bin zwar dankbar für die Antworten, habe aber erst kürzlich herausgefunden, dass Java 9 Optional eine neue Methode eingeführt hat, die mir am besten gefällt. Hier ist ein Beispiel.

Optional.ofNullable(user).ifPresentOrElse( u -> logger.info("User is:" + u.getEmail()),
  () -> logger.info("User not found"));
1
lapkritinis 22 Jän. 2019 im 10:49