短路 Java Optional.flatMap()

Short-circuiting Java Optional.flatMap()

这里有一个使用 Java 的 Optional.flatMap() 的有趣难题。我有一个 class,它以 "foo:bar""bar" 的形式封装了一个 CURIE。我还有一个 class 用于注册名称空间的前缀,以及跟踪默认名称空间。它有一个方法 findNamespaceByPrefix() 返回一个 Optional<URI> (因为前缀可能没有注册)和一个方法 getDefaultNamespace(),也返回一个 Optional<URI> (因为可能没有默认值命名空间)。

鉴于一些 CURIE,我想找到命名空间。使用这个很诱人:

Optional<URI> namespace = curie.getPrefix()
    .flatMap(this::findNamespaceByPrefix)
    .or(this::getDefaultNamespace);

但这是错误的。问题是它 returns 默认命名空间,即使有前缀但没有命名空间与该前缀相关联。如果 CURIE 中根本没有指示前缀,我们只想取回默认命名空间(如果有的话)。

这是一个解决方案:

Optional<String> prefix = curie.getPrefix();
Optional<URI> namespace = prefix.isPresent()
    ? prefix.flatMap(this::findNamespaceByPrefix)
    : getDefaultNamespace();

我对此很满意,但我觉得它使用三元运算符有点不起作用,使用 Optional.isPresent() 通常表明有更好的方法来做事。

Optional 专家有更好、更实用的 "short-circuit" 平面映射解决方案吗? (我有一种预感,我可以在管道中使用 Optional:ofOptional:get 进行多层包装和展开 Optional 来做一些事情,但是有没有更优雅的东西?)

而不是 "flatMapping" 你应该保留你的第二级可选:

Optional<URI> namespace = curie.getPrefix()
    .map(Application::findNamespaceByPrefix)
    .orElseGet(Application::getDefaultNamespace);

map 操作将前缀(如果存在)映射到包装的 Optional<Optional<URI>> 中,该 Optional<Optional<URI>> 为空(如果没有前缀)或包含空的 Optional<URI> (如果找不到前缀的名称空间)或包含实际的名称空间。

并且外部 orElseGet 仅在包装 Optional 为空且您的前缀不存在时才会被调用。

您检查空前缀

Optional<URI> namespace = prefix
   .filter(Objects::nonNull)
   .flatMap(this::findNamespaceByPrefix)
   .or(this::getDefaultNamespace);

您可以按如下方式进行测试:

    public static void main(String[] args) {
        test(Optional.ofNullable(null));
        test(Optional.ofNullable("yourprefix"));
    }

    private static void test(Optional<String> prefix) {
        Optional<URI> namespace2 = prefix
                .filter(Objects::nonNull)
                .flatMap(p -> Optional.of(URI.create(p)))
                .or(() -> Optional.of(URI.create("default")));

        System.out.println(namespace2);
    }