【问题标题】:Replace class methods with lambda expressions, is it bad practice?用 lambda 表达式替换类方法,这是不好的做法吗?
【发布时间】:2022-01-11 02:52:59
【问题描述】:

我有几个问题很难找到答案,至少在 Java 中是这样。

我在教程中看到了一个类定义,其中 lambda 的使用类似于方法。所以我很好奇除了简洁的代码和风格偏好之外是否还有其他好处。

例子:

public class Blocks {
    private Deque<Block> entries;

    public Blocks() {
        this.entries = new ArrayDeque<>();
    }

    public Deque<Block> getEntries() {
        return entries;
    }

    public void setEntries(Deque<Block> entries) {
        this.entries = new ArrayDeque<>(entries);
    }

    public Predicate<Block> push = entries::offerLast;

    public Supplier<Optional<Block>> peek = () -> Optional.ofNullable(entries.peekLast());

    public BooleanSupplier isEmpty = entries::isEmpty;

    public Supplier<String> lastHash = () -> peek.get().map(Block::hash).orElse("0");

    public LongSupplier size = entries::size;
}

这是一个有效的类定义吗?这是一个不好的做法吗?如果有,为什么?

我注意到的一件事是,在谓词推送中,我收到以下警告:

Dereference of 'entries' will produce 'NullPointerException'

如果应实例化条目,为什么我会收到此警告?该警告似乎会影响具有方法引用的任何函数。如果改为:

public Predicate<Block> push = block -> entries.offerLast(block);

然后警告消失。

【问题讨论】:

  • 这是有效的代码,但处理起来很尴尬,我怀疑它对简洁性有任何改进。要真正将某些东西推入双端队列,如果您将其定义为“常规”方法,则必须调用 push.test(block); 而不仅仅是 push(block)。像这样的代码很快就会变得混乱。其他变量也有同样的问题,所以我认为这是不好的做法。
  • 是的,我意识到了这一点。推送并没有真正打扰我,因为它返回一个布尔值。所以, push.test 以这种方式是有意义的。但是,是的,我绝对同意你的观点,这很尴尬。知道为什么带有方法引用的函数会发出警告吗?

标签: java class lambda functional-interface


【解决方案1】:

类的字段初始化程序在构造函数之前以文本顺序运行。因此,pushisEmpty 等字段将在 entries 在构造函数中被初始化之前被初始化。

当评估诸如entries::offerLast 之类的方法引用表达式时,首先评估entries 以确定应在哪个对象上调用该方法。但是,由于在计算方法引用表达式时未初始化 entries,因此 entries 的计算结果为 null。这会导致NullPointerException 被抛出。 JLS 15.13.3

首先,如果方法引用表达式以 ExpressionName 或 Primary 开头,则计算此子表达式。如果子表达式的计算结果为 null,则会引发 NullPointerException,并且方法引用表达式会突然完成。

要解决此问题,您可以将 entires 字段的初始化移出构造函数,并与它的声明内联:

private Deque<Block> entries = new ArrayDeque<>();

或者,您可以使用 lambda 表达式代替方法引用:

public Predicate<Block> push = e -> entries.offerLast(e);

【讨论】:

  • 谢谢,有道理。写这样的类是不好的做法吗?还是只是一种风格偏好?
  • @essentialz 我会说是的,这是一种不好的做法,不,这不是一种风格偏好。 Java 并非旨在以这种方式编写。这至少打破了principle of least astonishment
  • 好的,感谢您回答我的所有问题。我肯定会避免以这种方式使用函数。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-07
  • 1970-01-01
  • 2013-08-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多