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



我有一个方法,以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个可能的退出点:

  1. optA empty -> "ERR_1"
  2. optA not empty &&optB empty -> "ERR_2"
  3. 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只传播其"空"。

如果您可以将findAfindB更改为返回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);

最新更新