我有一个方法,以String
作为输入,也应该返回String
。
下面的ASCII图展示了逻辑流程:
Option<A> optA = finder.findA(input);
optA
/
isEmpty() / isDefined()
/
"ERR_1" Option<B> optB = finder.findB(optA.get().bid);
/
isEmpty() / isDefined()
/
"ERR_2" opt2.get().id
基本上对于给定的input
,我正在寻找在Option
中返回包装的A
对象。然后是A
存在,我正在寻找B
-也包装在Option
中,否则返回ERR_1
。如果B
存在,则返回它的id,否则返回ERR_2
。
我想知道如何使用可选(或模式匹配?)以一种简洁的方式(没有任何ifology)实现它-可能在一行中。
谁能给点建议?源代码可以在这里找到。
看起来你有3个可能的退出点:
- optA empty -> "ERR_1"
- optA not empty &&optB empty -> "ERR_2"
- both not empty -> optB.get().bid
你可以通过使用Javaslang:
实现这一点 optA
.map(a -> finder.findB(a.bid)
.map(b -> b.bid)
.getOrElse("ERR_2"))
.getOrElse("ERR_1");
如果optA
为空,我们将直接跳转到orElse("ERR_1")
如果optA
不为空,则在optB
为空的情况下,使用内部存储的值来获取b.bid
或"ERR_2"
的值。
同样,在纯Java 8中,它看起来像这样:
optA
.map(a -> finder.findB(a.bid)
.map(b -> b.bid)
.orElse("ERR_2"))
.orElse("ERR_1");
由于您使用的是javaslang, Try
似乎是一个更好的选择,因为它通过链传播错误,而Option只传播其"空"。
如果您可以将findA
和findB
更改为返回Try
,则得到:
Try<B> b = finder.findA(input)
.flatMap(a -> finder.findB(a.bid))
如果不能,则:
Try<B> b = finder.findA(input).toTry(() -> new Exception("ERR_1"))
.flatMap(a -> findB(a.bId).toTry(() -> new Exception("ERR_2")))
得到一个暂定的B
,我不确定你是否想把有效值和错误折叠成相同的值,如果是这样的话:
String value = b.getOrElseGet(Throwable::getMessage)
如果您有创建无意义异常的问题,您可以在每个查找操作中使用Either
,其中左边的值是您的错误类型。这样似乎可以更好地对问题进行建模,但是可能会有更长的类型签名的缺点,这取决于您如何拆分表达式。
您可能希望将其调整到您的代码中,但这是我要使用的方法。
首先,为每个故障点隔离您想要封装的错误。
Supplier<? extends RuntimeException> missingAException = IllegalStateException::new;
Supplier<? extends RuntimeException? missingBException = IllegalStateException::new;
这样做允许您稍后编写lambda来提供特定的错误消息,如果您愿意的话。
现在,我们写可选选项。
Optional<A> optA = finder.find(input);
Optional<B> optB = finder.findB(optA.orElseThrow(missingAException));
要提取optB
,使用与提取optA
相同的模式。
B value = optB.orElseThrow(missingBException);