JAVA 8将谓词提取为字段或方法?

时间:2017-08-10 16:35:55

标签: java-8 java-stream predicates

提取具有多种用途的谓词的更简洁方法是什么?方法或类字段?

这两个例子:

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;
}

对我来说,野战方式看起来更好一点,但这是正确的方法吗?我有疑虑。

3 个答案:

答案 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将丢弃它。