提取具有多种用途的谓词的更简洁方法是什么?方法或类字段?
这两个例子:
1.Class Field
void someMethod() {
IntStream.range(1, 100)
.filter(isOverFifty)
.forEach(System.out::println);
}
private IntPredicate isOverFifty = number -> number > 50;
2.Method
void someMethod() {
IntStream.range(1, 100)
.filter(isOverFifty())
.forEach(System.out::println);
}
private IntPredicate isOverFifty() {
return number -> number > 50;
}
对我来说,野战方式看起来更好一点,但这是正确的方法吗?我有疑虑。
答案 0 :(得分:6)
通常你可以缓存创建成本高昂的东西,而这些无状态lambda 不是。无状态lambda将为整个管道创建单个实例(在当前实现下)。第一次调用是最昂贵的 - 基础Predicate
实现类将被创建和链接;但对于无国籍和有状态的lambdas,这只会发生一次。
有状态的lambda将为每个元素使用不同的实例,并且它可能有意义地缓存那些,但是你的例子是无状态的,所以我不会。
如果你仍然想要(为了我的阅读目的),我会在Predicates
课程中假设。它也可以在不同的类中重复使用,如下所示:
public final class Predicates {
private Predicates(){
}
public static IntPredicate isOverFifty() {
return number -> number > 50;
}
}
你还应该注意到,在流和Predicates.isOverFifty
内使用x -> x > 50
语义相同,会有不同的内存使用。
在第一种情况下,只会创建一个实例(和类)并将其提供给所有客户端;而第二个(x -> x > 50
)不仅会创建一个不同的实例,而且还会为每个客户创建一个不同的类(想想应用程序中不同位置使用的相同表达式)。发生这种情况是因为链接按CallSite
发生 - 而在第二种情况下,CallSite
始终不同。
但这是你不应该依赖的东西(甚至可能会考虑) - 这些对象和类可以快速构建并快速通过GC删除 - 无论何种需要 - 都可以使用它。
答案 1 :(得分:0)
要回答,最好如果为旧式Java扩展这些lambda表达式。您现在可以看到,这些是我们在代码中使用的两种方式。所以,答案是,这完全取决于你如何编写特定的代码段。
private IntPredicate isOverFifty = new IntPredicate<Integer>(){
public void test(number){
return number > 50;
}
};
private IntPredicate isOverFifty() {
return new IntPredicate<Integer>(){
public void test(number){
return number > 50;
}
};
}
答案 2 :(得分:0)
1)对于字段大小写,您将始终为每个新对象分配谓词。如果您有一些实例,喜欢,服务,那就没什么大不了的。但如果这是一个可以为N的值对象,这不是一个好的解决方案。另请注意,可能根本不会调用someMethod()
。一种可能的解决方案是将谓词设为static
字段。
2)对于方法案例,您每次都会为someMethod()
调用创建一次谓词。 GC将丢弃它。