返回基于成员变量或映射函数的子列表

时间:2012-03-20 16:10:53

标签: java generics functional-programming guava

我有一个pojo列表List<Pojo> pojoList;并且pojo.getColour();返回一个枚举实例。

我想这样做:

List<Pojo> newlist = new ArrayList<Pojo>();
for(Pojo pojo:pojoList){
  if(pojo.getColour() == Colour.Red){
    newList.add(pojo);
  }
}

我可以看到自己对其他类型的列表使用类似的函数,而不是重复大量的代码是一种使它成为通用和/或功能的方法?这样我就可以根据不同的规则创建不同类型的子列表了?

4 个答案:

答案 0 :(得分:6)

首先,我应该注意,如果您只想要一个包含匹配元素的新ArrayList,那么您在示例中的方式就可以了。在Java具有lambda表达式之前,你不会比它更简单或更好看。

由于您使用对此进行了标记,因此可以使用Guava执行此操作。您基本上是在谓词(== Color.Red)和函数(pojo.getColour())的组合上过滤原始列表。因此,如果您在Function<Pojo, Colour>上有一个名为COLOUR的静态最终Pojo(就像这样):

public static final Function<Pojo, Colour> COLOUR =
    new Function<Pojo, Colour>() {
      @Override public Colour apply(Pojo input) {
        return input.getColour();
      }
    };

你可以像这样创建这样的组合:

Predicate<Pojo> isRedPojo = Predicates.compose(
    Predicates.equalTo(Colour.Red), Pojo.COLOUR);

然后,您可以创建原始列表的过滤视图:

Iterable<Pojo> redPojos = Iterables.filter(pojoList, isRedPojo);

如果您愿意,可以将过滤后的视图复制到ArrayList

List<Pojo> copy = Lists.newArrayList(redPojos);

答案 1 :(得分:1)

您必须使您的类型实现检查的通用接口:

public interface Candidate {
  public boolean isAddable();
}

然后循环看起来像这样

List<Candidate> newlist = new ArrayList<Candidate>();
for(Candidate pojo:pojoList){
 if(pojo.isAddable()){
   newList.add(pojo);
 }
}

并且Pojo类必须实现接口:

public class Pojo implments Candidate {

  // ...

  @Override
  public boolean isAddable() {
    return isRed();
  }
}

答案 2 :(得分:1)

制作通用过滤器界面

public interface Filter<T>{
     public boolean match(T item);
}

使用过滤器制作方法

public <T> List<T> getFilteredList(List<T> oldList, List<T> filter){
   List<T> newlist = new ArrayList<T>();

   for(T item:oldList){
      if(filter.match(item)){
         newlist.add(item);
      }
   }

   return newlist;
} 

把它们放在一起

List<Pojo> myList = .. 

List<Pojo> redList = getFilteredList(myList,new Filter<Pojo>(){
      public boolean match(Pojo item){ return item.isRed()};
});

List<Pojo> blueList = getFilteredList(myList,new Filter<Pojo>(){
      public boolean match(Pojo item){ return item.COLOR== Color.BLUE};
 }); 

答案 3 :(得分:1)

根据您使用它的频率/您使用的多少个不同的过滤器(只有红色,只有绿色等),创建一个过滤器接口是有意义的 - 如果它只是检查isRed那么它可能也是很多代码,你最好用一个简单的静态方法。

这个设计的好处是你可以将它与你想要过滤的任何对象一起使用(参见下面的String示例)。

public static void main(String[] args) {
    List<Pojo> originalList = Arrays.asList(new Pojo(true), new Pojo(false), new Pojo(false));
    List<Pojo> filteredList = Utils.getFilteredList(originalList, new Filter<Pojo>() {
        @Override
        public boolean match(Pojo candidate) {
            return candidate.isRed();
        }
    });
    System.out.println(originalList.size()); //3
    System.out.println(filteredList.size()); //1

    //Now with strings
    List<String> originalStringList = Arrays.asList("abc", "abd", "def");
    List<String> filteredStringList = Utils.getFilteredList(originalStringList, new Filter<String>() {
        @Override
        public boolean match(String candidate) {
            return candidate.contains("a");
        }
    });
    System.out.println(originalStringList.size()); //3
    System.out.println(filteredStringList.size()); //2
}

public static class Utils {
    public static <T> List<T> getFilteredList(List<T> list, Filter<T> filter) {
        List<T> selected = new ArrayList<>();
        for (T t : list) {
            if (filter.match(t)) {
                selected.add(t);
            }
        }
        return selected;
    }
}

public static class Pojo {
    private boolean isRed;

    public Pojo(boolean isRed) {
        this.isRed = isRed;
    }

    public boolean isRed() {
        return isRed;
    }
}

public interface Filter<T> {

    /**
    * When passed a candidate object, match returns true if it matches the filter conditions,
    * or false if it does not.
    * @param candidate the item checked against the filter
    * @return true if the item matches the filter criteria
    */
    boolean match(T candidate);
}