我想使用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用于记录错误。logDetails.size() == 0这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,而是尝试在代码中明确表达您的意图。可读性更有价值。