加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

如何链接lambda与最内层范围内可用的所有可选值而不嵌套Optional

发布时间:2020-12-15 02:20:34 所属栏目:Java 来源:网络整理
导读:这是我的另一个问题的分支: How to chain Optional#ifPresent() in lambda without nesting? 但是,现在的问题是如何提供一个lambda解决方案,其中所有可选值都在最里面的范围内可用: B b = procA().flatMap(this::procB).orElseThrow(SomeException::new);/
这是我的另一个问题的分支: How to chain Optional#ifPresent() in lambda without nesting?

但是,现在的问题是如何提供一个lambda解决方案,其中所有可选值都在最里面的范围内可用:

B b = procA().flatMap(this::procB).orElseThrow(SomeException::new);

// Value from procA() is not available.

我原来的代码是:

void SomeMethod() {
    procA().ifPresent(a -> {
       procB(a).ifPresent(b -> {
          // Do something with a and b

          return;
       });
    });

    throw new SomeException();
}

我理解最内层范围内的回报是错误的.新的flatMap示例说明了正确的行为.

我使用ifPresent()而不是get()来避免潜在的运行时异常,我可能无法检查可选的isPresent()的值.

解决方法

我发现这个问题非常有趣,因为具有潜在空值返回的链式调用是一种常见的麻烦,而Optional可以大大缩短通常的空检查链.但问题在于功能流方法的本质隐藏了映射函数中的中间值.嵌套是一种让它们可用的方法,但是如果你已经意识到,如果调用链的长度增长,它也会变得烦人.

我想不出一个简单轻量级的解决方案,但如果项目的性质经常导致这些情况,这个util类可以帮助:

public static class ChainedOptional<T>
{
    private final List<Object> intermediates;

    private final Optional<T>  delegate;

    private ChainedOptional(List<Object> previousValues,Optional<T> delegate)
    {
        this.intermediates = new ArrayList<>(previousValues);
        intermediates.add(delegate.orElse(null));
        this.delegate = delegate;
    }

    public static <T> ChainedOptional<T> of(T value)
    {
        return of(Optional.ofNullable(value));
    }

    public static <T> ChainedOptional<T> of(Optional<T> delegate)
    {
        return new ChainedOptional<>(new ArrayList<>(),delegate);
    }

    public <R> ChainedOptional<R> map(Function<T,R> mapper)
    {
        return new ChainedOptional<>(intermediates,delegate.map(mapper));
    }

    public ChainedOptional<T> ifPresent(Consumer<T> consumer)
    {
        delegate.ifPresent(consumer);
        return this;
    }

    public ChainedOptional<T> ifPresent(BiConsumer<List<Object>,T> consumer)
    {
        delegate.ifPresent(value -> consumer.accept(intermediates,value));
        return this;
    }

    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)
        throws X
    {
        return delegate.orElseThrow(exceptionSupplier);
    }

    public <X extends Throwable> T orElseThrow(Function<List<Object>,X> exceptionSupplier)
        throws X
    {
        return orElseThrow(() -> exceptionSupplier.apply(intermediates));
    }
}

您可以通过包装Optional或普通值来使用它.然后,当您使用map方法链接方法调用时,它将在列表中存储当前值时提供新的ChainedOptional.最后(ifPresent或者ElseThrow),您不仅会获得最后一个值,还会获得所有中间值的列表.因为不知道将链接多少个调用,所以我找不到以类型安全的方式存储这些值的方法.

看这里的例子:

ChainedOptional.of(1)
               .map(s -> s + 1)
               .map(s -> "hello world")
               .map(s -> (String) null)
               .map(String::length)
               .ifPresent((intermediates,result) -> {
                   System.out.println(intermediates);
                   System.out.println("Result: " + result);
               })
               .orElseThrow(intermediates -> {
                   System.err.println(intermediates);
                   return new NoSuchElementException();
               });

// [1,2,hello world,null,null]
// Exception in thread "main" java.util.NoSuchElementException
//    at ... 

ChainedOptional.of(1)
               .map(s -> s + 1)
               .map(s -> "hello world")
               // .map(s -> (String) null)
               .map(String::length)
               .ifPresent((intermediates,11]
// Result: 11

希望这可以帮助.如果你想出一个更好的解决方案,请告诉我.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读