【问题标题】:Abusing Optional#map considering absent Optional#peek method滥用 Optional#map 考虑缺席 Optional#peek 方法
【发布时间】:2018-07-05 15:51:00
【问题描述】:

考虑以下类:

ClassA {
}

ClassB {
    private ClassA classA;

    // getters and setters
}

由于Optional 上没有可用的peek 方法,这是否被视为滥用Optional#map 方法:

return myService.findA()
        .flatMap(a -> myService.findB(a) // also returns optional
                    .map(b -> {
                            b.setClassA(a);
                            return b;
                        }))
        .map(d -> MyType.of(d)) // MyType being other class
        .orElse(MyType.empty());

也可以这样写:

Optional<ClassA> optionalA = myService.findA();

if (optionalA.isPresent()) {
    Optional<ClassB> optionalB = myService.findB(optionalA.get());

    if (optionalB.isPresent()) {
        ClassB classB = optionalB.get();
        classB.setClassA(optionalA.get());
        return MyType.of(classB);
}
return MyType.empty();

两种实现都执行相同的逻辑,是否应该优先于另一种?

【问题讨论】:

  • 恕我直言,(a)是的,那是滥用,因为map 可能不会有任何副作用,并且(b)“旧式”代码可能是一个更冗长的机器人,但它是很多,很多更清晰,更容易理解。
  • 同时java doc for peek说:这个方法的存在主要是为了支持调试。所以对于状态突变peekmap 使用什么是一个悬而未决的问题。请参阅peekmap vs peek
  • @AntonBalaniuc 也没有。 Optional 类中已经有 ifPresent,它明确地用于执行操作。
  • @tobias_k 不是“可能”而是“绝对”。传递给 map 的方法应该是函数,根据定义是纯函数。

标签: java java-8


【解决方案1】:

在我看来,myService.findB(a) 并没有暗示b.setClassA(a) 看起来很奇怪,因为它在范围内都有,但无论如何,这里没有必要滥用map

return myService.findA()
    .flatMap(a -> {
        Optional<B> oB = myService.findB(a);
        oB.ifPresent(b -> b.setClassA(a));
        return oB;
    })
    .map(MyType::of).orElse(MyType.empty());

【讨论】:

  • 比OP的版本更清晰(两者都是,恕我直言),但这不是像map一样滥用flatMap吗?
  • @tobias_k 原始版本中map 的问题在于它只是为了执行具有副作用的操作而添加的;它并没有真正将值映射到其他东西。我的答案的flatMap 仍然以预期的方式使用,以执行计算为另一个Optional 的操作。如果还是不服气,可以自行将myService.findB(a);oB.ifPresent(b -&gt; b.setClassA(a));封装成一个新方法,在flatMap中调用这个方法;如前所述,我希望findB 在语义上是操作的一部分时首先做到这一点。
【解决方案2】:

因此,当您应用功能设计原​​则时,您永远不会更新适当的状态。这意味着没有任何数据结构允许这样做(就像您的 ClassB 使用该设置器的情况一样)。您宁愿返回具有更新值的该类的新实例。如果您这样做,则无需“滥用”mapflatMap,但您可以改用闭包:

return myService.findA()
    .flatMap(a -> myService.findB(a).map(b -> b.copyWith(a)))
    .map(MyType::of)
    .orElse(MyType.empty());

【讨论】:

    【解决方案3】:

    我可能更喜欢第一个实现,因为 Optional 在转换中提供的主要功能,我认为最好好好利用它。

    【讨论】:

    • Optional 的主要特点是提供了一种以声明性和便捷的方式处理缺席影响的方法(尽管java.util.Optional 已损坏)
    猜你喜欢
    • 1970-01-01
    • 2021-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多