суббота, 4 апреля 2015 г.

removeAll с помощью Guava

У меня на работе возникла такая задача, удалить содержимое одной коллекции из другой, по определенным бизнес критериям (их несколько). Проще говоря удалить дублирующиеся элементы из коллекции, опираясь на какие-то свойства этих объектов. Конечно самым простым решением было, переопределить equals() и hashCode() для POJO , которые добавляются в коллекцию. И потом просто вызывать removeAll(). Но старшие разработчики нашей компании дали мне по рукам, за такой подход .  И сказали копать, в сторону Google -вой библиотечки Guava.
Вытерев слезы, я начал гуглить.

Guava, прежде известна как Google Collections, представляет собой набор библиотек, которые используются в нескольких продуктах Google. Значительная часть библиотеки посвящена коллекциям.
Вам следует обратиться к Guava, если, например, вам нужны:
  • Коллекции с ориентацией на многопоточное исполнение — попробуйте ImmutableCollections (неизменные коллекции).
  • Легко подсчитать количество появлений конкретного элемента в множестве — вас выручат MultiSet и SortedMultiSet.
  • Хотите реализовать непомеченный ориентированный граф? Лучший помощник — Multimap.
  • Требуется реализация карты, в которой ключи и значения уникальны и их можно использовать как ключи для поиска значений? Двунаправленная карта Guava будет очень кстати.
   Но речь сегодня пойдет о других возможностях  этой библиотеки. И так у нас есть класс работников фирмы :
public class Employee {
    private String name;
    private String position;
    private int age;

    public Employee(String name, String position, int age) {
        this.name = name;
        this.position = position;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "\nName: "+name+" position: "+position+" age: "+age;
    }
}

Также есть у нас коллекция всех работников компании. Приходит к нам как-то директор нашей компании и говорит:

- Знаешь, я тут подготовил список работников которые подпадают под сокращение. Кризис знаешь ли. Твоя задача удалить их из списка всех работников компании.

На вход нам будет приходить коллекция со списком работников которые будут уволены. Нам остается удалить содержимое одной коллекции из другой. В этом нам поможет статический метод из класса Iterables - removeIf()  он получает на вход коллекцию по которой надо пробежаться, а также объект реализующий интерфейс Predicate. Если мы посмотрим на исходный код интерфейса Predicate то станет понятно что Predicate это Generic интерфейс. И Predicate -ом может стать любой класс нашего проекта, но он должен реализовать метод apply(T var) .
@GwtCompatible
public interface Predicate&ltT&gt {
    boolean apply(@Nullable T var1);

    boolean equals(@Nullable Object var1);
}
В методе apply  и будет происходить фильтрация элементов коллекции которые должны быть удалены. Соответственно если для элемента метод вернет true он будет удален. Что бы иметь доступ в методе apply к коллекции сотрудников что будут уволены мы обязательно должны сделать ее final.
Далее полный листинг программы:
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;

import java.util.ArrayList;
import java.util.List;


public class Main {
    public static void main(String[] args) {
        Employee employee1 = new Employee("John","CEO",43);
        Employee employee2 = new Employee("Bill","Developer",21);
        Employee employee3 = new Employee("Jess","Office Manager",25);
        Employee employee4 = new Employee("Liza","QA",22);
        Employee employee5 = new Employee("Jack","Team Lead",34);
        Employee employee6 = new Employee("Boris","BA",25);

        List&ltEmployee&gt employees = new ArrayList&ltEmployee&gt();
        
        employees.add(employee1);
        employees.add(employee2);
        employees.add(employee3);
        employees.add(employee4);
        employees.add(employee5);
        employees.add(employee6);

        System.out.println("Source Employees List: "+employees.toString());
        final List&ltEmployee&gt retiredEmployees = new ArrayList&ltEmployee&gt();
        
        retiredEmployees.add(employee3);
        retiredEmployees.add(employee5);
        retiredEmployees.add(employee1);

        System.out.println("Retired Employees List: "+retiredEmployees.toString());

        Iterables.removeIf(employees,new Predicate&ltEmployee&gt() {
            @Override
            public boolean apply(Employee employee) {
                for (Employee retiredEmployee : retiredEmployees) {
                    if (retiredEmployee == null || employee == null) {
                        return false;
                    }
                    boolean isNameEquals = employee.getName().equals(retiredEmployee.getName());
                    boolean isAgeEquals = employee.getAge()==retiredEmployee.getAge();
                    boolean isPositionEquals = employee.getPosition().equals(retiredEmployee.getPosition());

                    if (isNameEquals && isAgeEquals && isPositionEquals) {
                        return true;
                    }
                }
                return false;
            }
        });
        System.out.println("Result Employees List: "+employees.toString());

    }
}

Output:
>> Source Employees List: [
>>Name: John position: CEO age: 43,
>>Name: Bill position: Developer age: 21,
>>Name: Jess position: Office Manager age: 25,
>>Name: Liza position: QA age: 22,
>>Name: Jack position: Team Lead age: 34,
>>Name: Boris position: BA age: 25]

>>Retired Employees List: [
>>Name: Jess position: Office Manager age: 25,
>>Name: Jack position: Team Lead age: 34,
>>Name: John position: CEO age: 43]

>>Result Employees List: [
>>Name: Bill position: Developer age: 21,
>>Name: Liza position: QA age: 22,
>>Name: Boris position: BA age: 25]


Как видим это не самый лучший день для Jess, Jack-а и John -а. Вот такой вот маленький пример для демонстрации возможностей фреймворка Guava. Там есть еще много всего вкусного для работы с коллекциями. Ресерчьте , вникайте, юзайте ! 

Комментариев нет:

Отправить комментарий