Utils类中的谓词应该作为常量还是静态方法提供?

时间:2016-02-03 12:38:32

标签: java guava predicate

最近,我一直在使用谓词和番石榴实用程序。我创建了一个Utils.class,我存储了一些我在代码的不同部分使用的谓词。因此,这个问题出现了,我们(我和我的同事)没有就此达成一致。

将谓词放在实用程序类中的正确方法或“良好实践方式”是什么?作为用大写字母或静态方法定义它的常量?接下来,我写一个例子:

public final class Utils {

public static final Predicate<Element> IS_SPECIAL = new Predicate<Element>() {
    @Override
    public boolean apply(Element elem) {
        return elem.special;
    }
};


public static Predicate<Element> isSpecial() {
    return new Predicate<Element>() {
        @Override
        public boolean apply(Element elem) {
        return elem.special;
    }}

顺便说一句,番石榴提供了一些预定义的谓词,它提供了一个返回谓词的方法,但是其他的libreries也提供了它们作为常量。

4 个答案:

答案 0 :(得分:7)

有两种观点:API和实现。

关于API,使用方法的解决方案 比其他方法更灵活。它允许在不关心代码的情况下更改实现,这意味着您的代码不会受到隐藏在方法后面的任何更改的影响。

关于实施,人们通常使用枚举。枚举优于常数的优点很多:

  1. 这是线程安全的。如果使用单例变量,如果处理不当,您仍然可能会遇到内存问题。枚举是语言的一部分,定义将强制每个枚举常量一致地加载。
  2. 正如rinde在评论中提到的,枚举是可序列化的。这意味着您可以保留谓词以供进一步参考。
  3. 枚举提供了一种子命名空间。如果你想创建几个谓词,它们都可以在同一个地方定义,这样就可以很容易地找到它们。
  4. 枚举不会使用显式子类污染代码,并且每隔几行就不会看到new Predicate<Element>。然而,这些枚举的性质使得在编译的类中不可能具有相同的内容。所以在这里,它在源代码级别上纯粹更好。当然,这就是你想要的,因为你实际上是在编写源代码。
  5. 以下是我将如何做的一个例子。 (是的,我甚至会根据最近的Java默认惯例将Utils重命名为Elements

    public final class Elements {
      private static enum ElementPredicate implements Predicate<Element> {
        SPECIAL {
          @Override public boolean apply(Element e) { return e.special; }
        }
      }
    
      public static Predicate<Element> isSpecial() {
        return ElementPredicate.SPECIAL;
      }
    
      private Elements() {}
    }
    

    最后请注意,如果您使用的是Java 8,那么您应该坚持使用lambda机制,正如Louis Wasserman在问题评论中提到的那样。但是由于lambas在你的例子中不可用,因为你不是从方法中直接检索特殊而是直接从字段中检索特殊的,所以不幸的是,这个建议是无效的。但是,如果isSpecial()上有Element方法,则可以直接在代码中编写谓词,如下所示:

    Stream<T> stream = ... ;
    stream
        .filter(Element::isSpecial)
    

答案 1 :(得分:5)

正如其他答案所指出的,两个解决方案之间存在差异:静态常量实例化单个对象,但此对象永远不会被垃圾收集,而该方法每次调用时都会实例化一个新对象。但性能上的差异可以忽略不计:谓词的内存占用量非常小,垃圾收集器擅长收集短期对象。

由于灵活性,我仍然会选择方法解决方案:如果需要,您可以重构该方法以返回(私有)静态变量,而不会破坏任何旧代码。但是公共静态变量保持公共静态变量。

答案 2 :(得分:4)

我可能会这样做......

public final class Utils {    
    private static final Predicate<Element> IS_SPECIAL = new Predicate<Element>() {
        @Override
        public boolean apply(Element elem) {
            return elem.special;
        }
    };

    public static Predicate<Element> isSpecial() {
        return IS_SPECIAL;
    }
}

这样你就把它称为方法,但每次都不实例化谓词......

答案 3 :(得分:0)

每次调用谓词时,

isSpecial()都会创建一个新的谓词实例。因此我会选择IS_SPECIAL