短路 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:of
和 Optional: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);
}
这里有一个使用 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:of
和 Optional: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);
}