4

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

两个例子:

1.类字段

void someMethod() {
    IntStream.range(1, 100)
        .filter(isOverFifty)
        .forEach(System.out::println);
}

private IntPredicate isOverFifty = number -> number > 50;

2.方法

void someMethod() {
    IntStream.range(1, 100)
        .filter(isOverFifty())
        .forEach(System.out::println);
} 

private IntPredicate isOverFifty() {
    return number -> number > 50;
}

对我来说,现场方式看起来更好一点,但这是正确的方式吗?我有疑问。

4

3 回答 3

7

通常,您缓存创建成本高昂的东西,而这些无状态 lambda 则不是。无状态 lambda 将为整个管道(在当前实现下)创建一个实例。第一次调用是最昂贵的——Predicate将创建并链接底层实现类;但这对于无状态和有状态的 lambda 只发生一次。

有状态的 lambda 将为每个元素使用不同的实例,缓存这些实例可能有意义,但您的示例是无状态的,所以我不会。

如果你仍然想要那个(我假设是为了阅读目的),我会在课堂上做,Predicates让我们假设。它也可以在不同的类中重用,如下所示:

 public final class Predicates {
     private Predicates(){
     }

     public static IntPredicate isOverFifty() {
          return number -> number > 50;
     }
 } 

您还应该注意到,在Predicates.isOverFiftyStream 内部的用法x -> x > 50虽然在语义上相同,但会具有不同的内存使用情况。

在第一种情况下,只会创建一个实例(和类)并将其提供给所有客户端;而第二个 ( x -> x > 50) 不仅会创建一个不同的实例,还会为它的每个客户端创建一个不同的类(想想在应用程序的不同位置使用相同的表达式)。发生这种情况是因为链接发生在每个CallSite- 并且在第二种情况下CallSite总是不同的。

但这是你不应该依赖(甚至可能考虑)的东西 - 这些对象和类可以快速构建并且可以快速被 GC 删除 - 无论适合你的需要 - 使用它。

于 2017-08-10T17:26:49.263 回答
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;
          }

   };
}
于 2017-08-10T16:42:19.730 回答
0

1)对于现场情况,您将始终为每个新对象分配谓词。如果您有一些实例,喜欢,服务,这没什么大不了的。但是如果这是一个可以为 N 的值对象,这不是一个好的解决方案。还要记住,它someMethod()可能根本不会被调用。一种可能的解决方案是将谓词作为static字段。

2)对于方法案例,您将每次someMethod()调用一次创建谓词。GC之后会丢弃它。

于 2017-08-10T17:37:08.500 回答