2012-03-20 29 views
1

我有一個pojo的列表List<Pojo> pojoList;和pojo.getColour();返回一個Enum實例。根據成員變量或映射函數返回一個子列表

而且我想這樣做:

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

我可以使用類似的功能,對其他類型的列表,以便而不是重複了很多代碼看自己是他們的一種方法,使它通用和/或功能?這樣我可以根據不同的規則創建不同類型的子列表?

回答

6

首先,我要指出的是,如果你只是想要一個新ArrayList包含匹配的元素,你這樣做是在您的示例的方式就好了。在Java有lambda表達式之前,你不會比它更簡單或者更好看。

既然你這個標記與,這裏是你如何能番石榴做到這一點。你基本上過濾了謂詞組成中的原始列表(== Color.Red)和函數(pojo.getColour())。所以,如果你有一個靜態的最終Function<Pojo, Colour>稱爲COLOURPojo(像這樣):

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); 
+2

apache commons-collections也有很好的工具。 Collection filtered = CollectionUtils.filter(pojoCollection,new Predicate(){...}); – Matt 2012-03-20 17:52:12

+2

@Matt:我認爲commons-collections過濾器方法_removes_元素與原始集合不匹配,我不太喜歡。番石榴有更明確的名稱'Iterables.removeIf(Iterable,Predicate)'方法來做到這一點。 – ColinD 2012-03-20 18:12:49

+0

你能指定'Function'的外觀嗎? – hakunami 2015-07-14 06:40:32

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(); 
    } 
} 
+0

我認爲需要'Candidate'實施以限定恰好一個準則選擇要素('isAddable()'實現)被限制太多。基於謂詞/匹配的方法允許任意數量的不同方式來過濾元素。 – ColinD 2012-03-20 16:49:43

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

取決於你如何使用它往往/有多少不同的過濾器(只紅色,只有綠等。)你正在使用,創建一個Filter接口是有意義的 - 如果只是檢查isRed,那麼它可能是太多的代碼,你最好用一個簡單的靜態方法。

有關此設計的好處是您可以將它與任何要過濾的對象一起使用(請參閱下面的字符串示例)。所有的

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