如何使用可选项实现这个嵌套流程?
How to implement this nested flow with optionals?
我有一个方法将 String
作为输入并且还应该 return 一个 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
,我正在寻找 A
对象,它被 return 包裹在 Option
中。然后 A
存在 我正在寻找 B
- 也包含在 Option
中,否则 return ERR_1
。然后如果 B
存在 return 它是 id,否则 return ERR_2
.
我想知道如何以一种简洁明了的方式(没有任何 ifology)使用可选项(或者可能是模式匹配?)来实现它 - 可能是在一行中.
有人可以提出建议吗?
可以找到试用的源代码here。
您可能希望根据您的代码进行调整,但我会使用这种方法。
首先,为每个故障点隔离要封装的错误。
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);
您似乎有 3 个可能的退出点:
- optA 为空 -> "ERR_1"
- optA 不为空 && optB 为空 -> "ERR_2"
- 两者都不为空 -> optB.get().bid
您可以使用 Java俚语来实现:
optA
.map(a -> finder.findB(a.bid)
.map(b -> b.bid)
.getOrElse("ERR_2"))
.getOrElse("ERR_1");
如果optA
为空,我们将直接跳转到orElse("ERR_1")
如果optA
不为空,我们将使用存储在内部的值来获取值b.bid
或"ERR_2"
,如果optB
为空。
此外,在纯 Java 8 中,它看起来像这样:
optA
.map(a -> finder.findB(a.bid)
.map(b -> b.bid)
.orElse("ERR_2"))
.orElse("ERR_1");
由于您使用的是 javaslang,Try
似乎是更好的选择,因为它通过链传播错误,而 Option 仅传播其 "emptiness".
如果您可以将 findA
和 findB
更改为 return 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
,其中左边的值是您的错误类型。这似乎可以更好地模拟问题,但可能会有较长类型签名的缺点,具体取决于您如何拆分表达式。
我有一个方法将 String
作为输入并且还应该 return 一个 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
,我正在寻找 A
对象,它被 return 包裹在 Option
中。然后 A
存在 我正在寻找 B
- 也包含在 Option
中,否则 return ERR_1
。然后如果 B
存在 return 它是 id,否则 return ERR_2
.
我想知道如何以一种简洁明了的方式(没有任何 ifology)使用可选项(或者可能是模式匹配?)来实现它 - 可能是在一行中.
有人可以提出建议吗?
可以找到试用的源代码here。
您可能希望根据您的代码进行调整,但我会使用这种方法。
首先,为每个故障点隔离要封装的错误。
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);
您似乎有 3 个可能的退出点:
- optA 为空 -> "ERR_1"
- optA 不为空 && optB 为空 -> "ERR_2"
- 两者都不为空 -> optB.get().bid
您可以使用 Java俚语来实现:
optA
.map(a -> finder.findB(a.bid)
.map(b -> b.bid)
.getOrElse("ERR_2"))
.getOrElse("ERR_1");
如果optA
为空,我们将直接跳转到orElse("ERR_1")
如果optA
不为空,我们将使用存储在内部的值来获取值b.bid
或"ERR_2"
,如果optB
为空。
此外,在纯 Java 8 中,它看起来像这样:
optA
.map(a -> finder.findB(a.bid)
.map(b -> b.bid)
.orElse("ERR_2"))
.orElse("ERR_1");
由于您使用的是 javaslang,Try
似乎是更好的选择,因为它通过链传播错误,而 Option 仅传播其 "emptiness".
如果您可以将 findA
和 findB
更改为 return 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
,其中左边的值是您的错误类型。这似乎可以更好地模拟问题,但可能会有较长类型签名的缺点,具体取决于您如何拆分表达式。