3

我正在研究从 Objective C 移植到 Java 的代码库。没有空检查的方法链接有几种用法

dog.collar().tag().name()

我正在寻找类似于安全取消引用运算符的东西?在 Groovy 中,而不是使用 nullchecks

dog.collar?.tag?.name

这导致Maybe monad有了 Nothing 而不是 Null 的概念。但是当访问值时,我遇到的所有 Nothing 实现都抛出异常,这仍然不能解决链接问题。我让 Nothing 返回一个模拟,其行为类似于 NullObject 模式。但它解决了链接问题。

这个 Nothing 的实现有什么问题吗?

public class Nothing<T> implements Maybe<T> {

    private Class<T> klass;

    public Nothing(Class<T> klass) {
        this.klass = klass;
    }

    @Override
    public T value() {
        return mock(klass, Mockito.RETURNS_DEEP_STUBS); 
    }
}

据我所知

  1. 在代码中使用模拟库感觉很奇怪
  2. 它不会在第一个 null 处停止。
  3. 由于空引用或名称实际上为空,我如何区分空结果?它在 Groovy 代码中是如何区分的?
4

4 回答 4

7

我真的不建议只检查空值。真的,我建议不要返回 null,而是抛出异常。

在任何一种情况下,您都不会通过执行此空对象方法来使代码更快,而且我认为您最终只会因为您想复制不同编程语言的功能而使某人感到困惑。我认为你应该适应你使用的语言。

于 2010-05-24T20:45:38.457 回答
4

我也喜欢这个运算符,但它在 Java 上不可用——另外,它是草率代码的权宜之计:如果 dog.collar 没有标签,它可能应该以不同的方式分支,如果标签没有没有名字——它可能是一个错误,应该抛出一个异常。

并不是说当您继承不是您编写的代码时说“代码更好”可以解决任何问题。

我建议你首先重构你的代码——如果这样的代码到处都在发生,也许它无论如何都需要移动到一个集中的函数中。如果 dog.getName() 委托给 dog.collar() 来获取它的标签,最后是标签的名字,那么你只需要在一个地方修复这个错误(狗必须有一个名字,即使它不在项圈上,所以 dog.getName 应该能够遍历任何路径来解决你的问题——现在再为下一个糟糕的代码点做一遍。

每当您看到自己在 2 个地方修补相同的代码时,就会出现因式分解问题。如果这对每组属性只发生一次(如果它已经完全分解和 OO),那么它不会是一个严重的问题,只是几个补丁。

哎呀,这样的代码难道不违反一些熟悉的规则吗?

于 2010-05-24T20:52:58.700 回答
1

您可以使用闭包将其显式实现为可能是 monad。

我在遇到您的问题的同时遇到了这个问题。
http://groovyconsole.appspot.com/script/205001

这 ?。安全解除引用在 groovy 中显然在语法上更干净,用于检查 null,您可以用 ?: 结束链以返回 Nothing 值而不是 null,例如在此上下文中的 ""。

如果您想了解 monad,我建议您学习 Haskell,然后您自然会开始了解这些概念如何以及如何在其他语言中使用。允许可变性的语言,即使是功能性的(例如 Scala)也经常展示“不纯”的解决方案,而不是纯粹的功能性解决方案。

于 2010-12-24T15:18:03.567 回答
-2

Java 中没有“安全解除引用”运算符。

我认为这是一件好事,因为“安全解除引用”通常是一个伪装的错误。你基本上有两种可能性:

  • 该值不应为 null。在这种情况下,null 表示您的假设存在严重错误,如果 null 以某种方式出现,您应该抛出 NullPointerException(这是快速失败的原则
  • 该值可以是 null。在这种情况下,您通常应该进行一些比“不调用此方法”更复杂的显式空处理。您必须思考:在这种情况下, null意味着什么?

就个人而言,我通常将长方法链视为将代码重构为更小、名称清晰的方法的提示(如果需要,可以在内部封装适当的 null 处理)。在大多数情况下,这可能比引入 monad 更明智。

于 2012-09-09T01:41:07.317 回答