用 lambda 表达式替换 class 方法,这是不好的做法吗?
Replace class methods with lambda expressions, is it bad practice?
我有几个问题很难找到答案,至少在 Java。
我在教程中看到 Class 定义,其中 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;
}
这是一个有效的 class 定义吗?这是一种不好的做法吗?如果是,为什么?
我注意到的一件事是,在谓词推送中,我收到以下警告:
Dereference of 'entries' will produce 'NullPointerException'
如果应该实例化条目,为什么我会收到此警告?该警告似乎会影响任何带有方法引用的函数。如果改为:
public Predicate<Block> push = block -> entries.offerLast(block);
然后警告消失。
class 运行 的字段初始值设定项,按文本顺序,在构造函数之前。因此,字段 push
、isEmpty
等将在 entries
在构造函数中初始化之前被初始化。
当计算方法引用表达式如entries::offerLast
时,首先计算entries
以确定应该在哪个对象上调用该方法。但是,由于 entries
在评估方法引用表达式时未初始化,因此 entries
评估为空。这会导致抛出 NullPointerException
。 JLS 15.13.3
First, if the method reference expression begins with an ExpressionName or a Primary, this subexpression is evaluated. If the subexpression evaluates to null, a NullPointerException is raised, and the method reference expression completes abruptly.
要解决此问题,您可以将 entires
字段的初始化移出构造函数,并与其声明内联:
private Deque<Block> entries = new ArrayDeque<>();
或者,您可以使用 lambda 表达式代替方法引用:
public Predicate<Block> push = e -> entries.offerLast(e);
我有几个问题很难找到答案,至少在 Java。
我在教程中看到 Class 定义,其中 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;
}
这是一个有效的 class 定义吗?这是一种不好的做法吗?如果是,为什么?
我注意到的一件事是,在谓词推送中,我收到以下警告:
Dereference of 'entries' will produce 'NullPointerException'
如果应该实例化条目,为什么我会收到此警告?该警告似乎会影响任何带有方法引用的函数。如果改为:
public Predicate<Block> push = block -> entries.offerLast(block);
然后警告消失。
class 运行 的字段初始值设定项,按文本顺序,在构造函数之前。因此,字段 push
、isEmpty
等将在 entries
在构造函数中初始化之前被初始化。
当计算方法引用表达式如entries::offerLast
时,首先计算entries
以确定应该在哪个对象上调用该方法。但是,由于 entries
在评估方法引用表达式时未初始化,因此 entries
评估为空。这会导致抛出 NullPointerException
。 JLS 15.13.3
First, if the method reference expression begins with an ExpressionName or a Primary, this subexpression is evaluated. If the subexpression evaluates to null, a NullPointerException is raised, and the method reference expression completes abruptly.
要解决此问题,您可以将 entires
字段的初始化移出构造函数,并与其声明内联:
private Deque<Block> entries = new ArrayDeque<>();
或者,您可以使用 lambda 表达式代替方法引用:
public Predicate<Block> push = e -> entries.offerLast(e);