如何在Java 8中使用分隔符连接两个可选的<String>

spi*_*lok 12 java optional java-8

我有两个Optional字符串,name1name2.我想加入这两个,结果也是一个可选的:

  1. 如果其中任何一个非空,则结果应为非空名称.
  2. 如果两者都非空,我希望结果与分隔符连接AND.
  3. 如果两者都为空,则结果应为空 Optional

我的尝试:

StringBuilder sb = new StringBuilder();
name1.ifPresent(sb::append);
name2.ifPresent(s -> {
    if (sb.length() > 0) {
        sb.append(" AND ");
    }
    sb.append(s);
}
Optional<String> joinedOpt = Optional.ofNullable(Strings.emptyToNull(sb.toString()));
Run Code Online (Sandbox Code Playgroud)

这很有效,但看起来很难看,而且功能不是很好.

PS:有一个类似的问题,但接受的答案是错误的.具体来说,如果name1为空而name2不是,则返回空的可选项.

shm*_*sel 15

一种解决方案是流和reduce():

Optional<String> joinedOpt = Stream.of(name1, name2)
        .filter(Optional::isPresent)
        .map(Optional::get)
        .reduce((a, b) -> a + " AND " + b);
Run Code Online (Sandbox Code Playgroud)

如其他人所建议的那样,随意用Java 9或Guava替换filter/map组合.

  • @shmosel并不总是从9开始 (5认同)
  • 连接总是在引擎盖下使用StringBuilder.但这种减少最多只能召唤一次. (2认同)

Sle*_*idi 7

Java 1.9中可能的解决方案是

 Optional<String> name1 = Optional.of("x");
 Optional<String> name2 = Optional.of("y");
 String s = Stream.concat(name1.stream(), name2.stream()).collect(Collectors.joining(" AND "));
 System.out.println(s);
Run Code Online (Sandbox Code Playgroud)

使用Java 1.8,您无法从Optional到Stream.但是,您可以非常轻松地将此类转换添加到Java 1.8.

static <T> Stream<T> of(Optional<T> option) {
    return option.map(Stream::of).orElseGet(Stream::empty);
}
Run Code Online (Sandbox Code Playgroud)

现在您可以使用该of方法来连接两个流.

现在,Optional如果没有结果,为了得到一个空,你可以将结果包装成一个Optional并做一个简单的过滤器.

Optional<String> result = Optional.of(collect).filter(Optional::isPresent);
Run Code Online (Sandbox Code Playgroud)