Java 中的 Null 安全取消引用,如 ?.在 Groovy 中使用 Maybe monad

发布于 2024-09-02 23:13:28 字数 1030 浏览 7 评论 0原文

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

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

我一直在寻找类似于 安全解引用运算符?在 Groovy 中而不是进行 nullchecks

dog.collar?.tag?.name

这导致 也许 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代码中如何区分?

I'm working on a codebase ported from Objective C to Java. There are several usages of method chaining without nullchecks

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

I was looking for something similar to safe-dereferencing operator ?. in Groovy instead of having nullchecks

dog.collar?.tag?.name

This led to Maybe monad to have the notion of Nothing instead of Null. But all the implementations of Nothing i came across throw exception when value is accessed which still doesn't solve the chaining problem. I made Nothing return a mock, which behaves like NullObject pattern. But it solves the chaining problem.

Is there anything wrong with this implementation of 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); 
    }
}

As far as I can see

  1. It feels odd to use mocking library in code
  2. It doesn't stop at the first null.
  3. How do i distinguish between null result because of null reference or name actually being null? How is it distinguished in Groovy code?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

書生途 2024-09-09 23:13:28

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

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

I wouldn't really recommend just checking for the nulls. Really, I recommend not even ever returning null, but instead throwing exceptions.

In either case, you are not going to make the code any faster by doing this null object method, and I think you'll just end up confusing someone just because you want to replicate the feature of a different programming language. I think you should just adapt to the language you're using.

羅雙樹 2024-09-09 23:13:28

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

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

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

每当您看到自己在两个位置修补相同的代码时,请再次执行此操作(如果仅此而已)。每组属性都会发生一次(如果它已经完全分解并且面向对象),那么它不会是一个严重的问题,只是几个补丁而已,

哎呀,这样的代码是否违反了一些熟悉的规则?

I love this operator as well, but it's not available on Java--plus it's a stop-gap patch for sloppy code: If a dog.collar doesn't have a tag, it should probably branch differently, and if a tag doesn't have a name--it's probably an error and should throw an exception.

Not that it solves anything to say "code better" when you are inheriting code you didn't write.

I suggest that first you refactor your code--if code like that is happening all over the place, perhaps it needs to be moved into a centralized function anyway. If dog.getName() delegates to dog.collar() to get it's tag and finally the tag's name, then you only have to fix this bug in one place (The dog has to have a name even if it's not on the collar, so dog.getName should be able to traverse any path to solve your problem--now do it again for the NEXT spot of crappy code.

Whenever you see yourself patching the same code in 2 places, there is a factoring issue. If this only happens once for each group of attributes (if it's already fully factored and OO) then it can't be a serious problem, just a couple patches.

Heck, doesn't code like this even violate a few rules of familiarity?

む无字情书 2024-09-09 23:13:28

您可以使用闭包来显式地实现它,就像 monad 一样。

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

?.安全解引用显然在 groovy 中对于 null 检查在语法上更清晰,您可以用 ?: 结束链以返回 Nothing 值而不是 null,例如在此上下文中的“”。

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

You could use closures to explicitly implement this as maybe monad.

I ran across this the same time as I ran across your question.
http://groovyconsole.appspot.com/script/205001

The ?. safe dereferencing is obviously syntatically cleaner in groovy for null checking, you can end the chain with ?: to return a Nothing value instead of null, such as "" in this context.

If you want to understand monads I would recommend learning Haskell, and then you naturally start to see how these concepts can and are used in other languages. Languages that allow mutability, even if functionalish (such as Scala) often showcase "impure" solutions rather than purely functional ones.

生寂 2024-09-09 23:13:28

Java 中没有“安全取消引用”运算符。

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

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

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

There is no "safe-dereferencing" operator in Java.

I think this is a good thing, as "safe-dereferencing" is often a bug is disguise. You have basically two possibilities:

  • The value shouldn't ever be null. In which case a null indicates a serious error in your assumptions and you should be throwing a NullPointerException if a null somehow appears (this is the fail-fast principle)
  • The value can be null. In which case you typically should be doing some explicit null handling that is more sophisticated than just "don't call this method". You have to think: what does a null mean in this situation?

Personally, I usually see long method chains as a hint to refactor your code into smaller, clearly named methods (which can wrap up proper null handling inside if needed). This is probably more sensible than introducing monads in most circumstances.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文