【问题标题】:How to create a ArrayPredicate<A extends Object[]>?如何创建数组谓词<A extends Object[]>?
【发布时间】:2015-09-20 04:02:19
【问题描述】:

我不是要create an array of a generic type(例如E[])。我要做的是创建一个predicate 来分析(非原始)数组,例如

public class ArrayPredicate<A extends Object[]> implements Predicate<A> {    

   public boolean test(A a) {
      if(a == null) return false;
      if(a.length == 0) return false;
      for(Object o: a) {
         if(o == null) return false;
      } 
      return true;
   }    

   ...
}

但是Predicate&lt;Object[]&gt;显然是编译器错误。

更新:我需要将其扩展到StringArrayPredicateIntegerArrayPredicate 等等,以验证每个元素的具体值。因此,类本身必须是泛型的。

如何为数组创建泛型谓词?

【问题讨论】:

    标签: java arrays generics interface predicate


    【解决方案1】:

    如果您想要Predicate&lt;Object[]&gt;,则无需将实现类本身设为通用。

    这样编译:

    public class ArrayPredicate implements Predicate<Object[]> {    
    
        public boolean test(Object[] a) {
           if(a == null) return false;
           if(a.length == 0) return false;
           for(Object o: a) {
              if(o == null) return false;
           } 
           return true;
        }    
     }
    

    如果你确实想要参数化你的类:

    public class ArrayPredicate<T> implements Predicate<T[]> {
        public boolean test(T[] a) {
            return a != null && a.length > 0 && !Arrays.stream(a).filter(o -> o == null).findAny().isPresent();
        }
    }
    

    如果您愿意,请注意方法体的 java-8 重构。

    【讨论】:

    • 对这个编译感到惊讶。应该试过了我对类本身进行泛型化的需要是能够将其扩展到 String[] 谓词和 Integer[] 谓词......因此您可以验证每个元素的长度/值,例如。
    • @aliteralmind 查看通用解决方案的编辑(包括 java 8 Kung Fu 替代方案)。
    【解决方案2】:

    目前还不是很清楚你到底想达到什么目标。我假设您想创建一些通用解决方案来以相同的方式验证所有数组元素,然后将其专门用于各种元素类型。

    为了解决这个问题,我推荐以下方法。使ArrayPredicate&lt;T&gt; 不是类,而是另一个扩展Predicate&lt;T[]&gt; 并提供验证数组元素的抽象方法的接口。整个界面可能是这样的:

    import java.util.Arrays;
    import java.util.function.Predicate;
    
    @FunctionalInterface
    public interface ArrayPredicate<T> extends Predicate<T[]> {
        public boolean testElement(T t);
    
        default public boolean test(T[] a) {
            if (a == null || a.length == 0)
                return false;
            return Arrays.stream(a).allMatch(this::testElement);
        }
    }
    

    之后你可以像这样定义特定的谓词:

    public class NonNullArrayPredicate implements ArrayPredicate<Object> {
        @Override
        public boolean testElement(Object obj) {
            return obj != null;
        }
    }
    
    public class NonEmptyStringArrayPredicate implements ArrayPredicate<String> {
        @Override
        public boolean testElement(String str) {
            return str != null && !str.isEmpty();
        }
    }
    

    等等。尽管 Java-8 的方式可能是完全删除这些类并使用 lambda:

    ArrayPredicate<Object> nonNullObjectArrayPredicate = Objects::nonNull;
    ArrayPredicate<String> nonEmptyStringArrayPredicate = str -> str != null && str.isEmpty();
    

    另一种更实用的解决方案是完全摆脱 ArrayPredicate 并创建单个高阶函数,而不是将元素谓词转换为数组谓词:

    // In any suitable class
    public static <T> Predicate<T[]> forArray(Predicate<T> elementPredicate) {
        return a -> a != null && a.length != 0 &&
                    Arrays.stream(a).allMatch(elementPredicate);
        };
    }
    

    这样你可以像这样创建特定的谓词:

    Predicate<Object[]> nonNullObjectArrayPredicate = forArray(Objects::nonNull);
    Predicate<String[]> nonEmptyStringArrayPredicate = forArray(
                                         str -> str != null && str.isEmpty());
    

    因此您不需要声明任何新类,只需声明函数即可。

    【讨论】:

      猜你喜欢
      • 2011-03-05
      • 2018-02-01
      • 2011-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多