使用Optional.orElseGet 来做一些日志记录逻辑是个好主意吗

lap*_*nis 6 java

我想使用Optional来处理空值,我想不出最好的方法是什么的“棘手”部分 - 是我想在值为空时进行记录。我可以用下面的代码来实现这一点 - 但感觉很尴尬。

(更新:我已经发布了我自己的答案,其中包含 Java 9 中的可选)

可以说代码如下所示:

// logLine.getSomeProperty returns Optional<String>

List<LogDetails> logDetails = logLine.getSomeProperty()
    .map(this::extractLogDetails)
    .orElseGet(() -> logError(logLine));
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
List<LogDetails> logError(LogLine logLine) {
    log.error("Error while ... {} ", logLine));
    persistence.setErrorStatus(logLine, FAILED_PARSING);
    return new ArrayList<>();
}
Run Code Online (Sandbox Code Playgroud)

它会做我想做的事,但我有几个“问题”。

  • 我发现很奇怪,调用的方法orElseGet用于记录错误。
  • 我可以用 orElseThrow 和 logError 替换 orElseGet ,并且不要抛出任何东西 - 我也不喜欢。
  • logError 方法返回我不使用的列表,从应该为空的方法返回一些内容看起来很奇怪。
  • 只是必须有更好的方法
  • someProperty 不为空,但没有匹配项的情况 - 我也想记录,但为此我需要另一行代码来检查是否logDetails.size() == 0

jbx*_*jbx 4

orElseGet并不是真正的错误处理机制,而是作为一种生成不同默认值的方法,以防万一Optional未携带任何错误时生成不同默认值的方法。

如果您想Optional明确检查是否为空,只需使用该Optional.isPresent()检查,然后logError()在这种情况下执行该操作。

你首先需要思考的是,如果是Optional空的,你想做什么?除了记录错误之外,您还想继续处理空列表吗?

如果是,那么你可以有这样的东西:

List<LogDetails> logDetails = logLine.getSomeProperty()
    .map(this::extractLogDetails)
    .orElseGet(Collections::emptyList);
Run Code Online (Sandbox Code Playgroud)

之后你可以这样做:

if (logDetails.isEmpty()) {
  logError(logline);
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您根本不想有空列表,您可以将内容保留在可选级别。这样,无论是getSomeProperty()空的还是生成的列表为空的情况都会以相同的方式处理。

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

if (!logDetailsOpt.isPresent()) {
  logError(logLine);
}
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,logError()预计不会返回任何内容。它正在做它名义上要做的事情,记录错误。

不要试图过度使用 的功能Optional,而是尝试在代码中明确表达您的意图。可读性更有价值。