2012-03-20 2 views
1

У меня есть список pojo's 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 нет лямбда-выражений, вы не получите более простой или более красивый вид.

Поскольку вы отметили это с помощью , вот как вы можете сделать это с помощью 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); 
+2

В коллекции apache commons также есть хорошие утилиты для этого. Коллекция filter = CollectionUtils.filter (pojoCollection, новый Predicate() {...}); – Matt

+2

@Matt: Я думаю, что метод фильтров commons-collections _removes_, который не соответствует исходной коллекции, что мне не очень нравится. В Guava более явно используется метод 'Iterables.removeIf (Iterable, Predicate)' для этого. – ColinD

+0

Вы могли бы указать, что выглядит 'Function'? – hakunami

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

Я думаю, что требование реализации «Кандидат» для определения только одного критерия выбора элементов (реализация 'isAddable()') слишком ограничивает. Подход, основанный на предикате/сопряжении, позволяет использовать любое количество различных способов фильтрации элементов. – ColinD

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

В зависимости от того, как часто вы его используете/как много различных фильтров (только красный, только зеленый и т.д. .), который вы используете, может возникнуть смысл создать интерфейс фильтра - если нужно только проверить 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); 
} 
Смежные вопросы