如何使用可选项实现这个嵌套流程?

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 个可能的退出点:

  1. optA 为空 -> "ERR_1"
  2. optA 不为空 && optB 为空 -> "ERR_2"
  3. 两者都不为空 -> 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".

如果您可以将 findAfindB 更改为 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,其中左边的值是您的错误类型。这似乎可以更好地模拟问题,但可能会有较长类型签名的缺点,具体取决于您如何拆分表达式。​​