Как да филтрирам колекция в Java

1. Общ преглед

В този кратък урок ще разгледаме различни начини за филтриране на колекция в Java - тоест, намиране на всички елементи, които отговарят на определено условие.

Това е основна задача, която присъства на практика във всяко приложение на Java.

Поради тази причина броят на библиотеките, които предоставят функционалност за тази цел, е значителен.

По-специално, в този урок ще разгледаме:

  • Функция филтър () на Java 8 Streams
  • Java 9 филтриращ колектор
  • Съответни приложни програмни интерфейси (API) на Eclipse Collections
  • Методът на Apache CollectionUtils filter ()
  • Подходът на Guava's Collections2 filter ()

2. Използване на потоци

Откакто беше въведена Java 8, потоците спечелиха ключова роля в повечето случаи, когато трябва да обработим колекция от данни.

Следователно това е предпочитаният подход в повечето случаи, тъй като е изграден в Java и не изисква допълнителни зависимости.

2.1. Филтриране на колекция с потоци

За улеснение във всички примери нашата цел ще бъде да създадем метод, който извлича само четните числа от Колекция от целочислени стойности.

По този начин можем да изразим условието, което ще използваме, за да оценим всеки елемент като „ стойност% 2 == 0 “.

Във всички случаи ще трябва да дефинираме това условие като предикатен обект:

public Collection findEvenNumbers(Collection baseCollection) { Predicate streamsPredicate = item -> item % 2 == 0; return baseCollection.stream() .filter(streamsPredicate) .collect(Collectors.toList()); }

Важно е да се отбележи, че всяка библиотека, която анализираме в този урок, предоставя собствена реализация на Predicate , но въпреки това всички те са дефинирани като функционални интерфейси, което ни позволява да използваме функциите на Lambda, за да ги декларираме.

В този случай използвахме предварително дефиниран Collector, предоставен от Java, който натрупва елементите в Списък , но можехме да използваме и други, както беше обсъдено в предишната публикация.

2.2. Филтриране след групиране на колекция в Java 9

Потоците ни позволяват да обобщаваме елементи с помощта на колектора groupingBy .

И все пак, ако филтрираме, както направихме в последния раздел, някои елементи може да бъдат изхвърлени в ранен етап, преди този колектор да влезе в игра.

Поради тази причина, колекторът за филтриране е въведен с Java 9, с цел обработка на подколекциите, след като те са групирани.

Следвайки нашия пример, нека си представим, че искаме да групираме колекцията си въз основа на броя цифри, които има всяко цяло число, преди да филтрираме нечетните числа:

public Map
    
      findEvenNumbersAfterGrouping( Collection baseCollection) { Function getQuantityOfDigits = item -> (int) Math.log10(item) + 1; return baseCollection.stream() .collect(groupingBy( getQuantityOfDigits, filtering(item -> item % 2 == 0, toList()))); }
    

Накратко, ако използваме този колектор, може да завършим с празен запис на стойност, докато ако филтрираме преди групирането, колекторът изобщо няма да създаде такъв запис.

Разбира се, бихме избрали подхода въз основа на нашите изисквания.

3. Използване на Eclipse Collection

Можем да се възползваме и от някои други библиотеки на трети страни, за да постигнем нашата цел, било то поради това, че нашето приложение не поддържа Java 8, или защото искаме да се възползваме от някои мощни функционалности, които не се предоставят от Java.

Такъв е случаят с Eclipse Collections , библиотека, която се стреми да бъде в крак с новите парадигми, развивайки и възприемайки промените, въведени от всички най-нови версии на Java.

Можем да започнем с проучване на нашия уводен пост на Eclipse Collections, за да имаме по-широки познания за функционалността, предоставена от тази библиотека.

3.1. Зависимости

Нека започнем с добавяне на следната зависимост към pom.xml на нашия проект :

 org.eclipse.collections eclipse-collections 9.2.0 

На затъмнение-колекциите включва всички необходими данни за структурното интерфейси и на самата API.

3.2. Филтриране на колекция с колекции Eclipse

Нека сега използваме функцията за филтриране на eclipse в една от неговите структури от данни, като например MutableList :

public Collection findEvenNumbers(Collection baseCollection) { Predicate eclipsePredicate = item -> item % 2 == 0; Collection filteredList = Lists.mutable .ofAll(baseCollection) .select(eclipsePredicate); return filteredList; }

Като алтернатива, можем да съм използвал взаимодействаме е да изберете ()статичен метод за дефиниране на обект filteredList :

Collection filteredList = Iterate.select(baseCollection, eclipsePredicate);

4. Използване на CollectionUtils на Apache

За да започнем с библиотеката CollectionUtils на Apache , можем да разгледаме този кратък урок, в който разгледахме употребите му.

В този урок обаче ще се съсредоточим върху изпълнението на филтъра () .

4.1. Зависимости

Първо, ще се нуждаем от следните зависимости в нашия файл pom.xml :

 org.apache.commons commons-collections4 4.2 

4.2. Filtering a Collection with CollectionUtils

We are now ready to use the CollectonUtils‘ methods:

public Collection findEvenNumbers(Collection baseCollection) { Predicate apachePredicate = item -> item % 2 == 0; CollectionUtils.filter(baseCollection, apachePredicate); return baseCollection; }

We have to take into account that this method modifies the baseCollection by removing every item that doesn't match the condition.

This means that the base Collection has to be mutable, otherwise it will throw an exception.

5. Using Guava's Collections2

As before, we can read our previous post ‘Filtering and Transforming Collections in Guava' for further information on this subject.

5.1. Dependencies

Let's start by adding this dependency in our pom.xml file:

 com.google.guava guava 25.1-jre 

5.2. Filtering a Collection with Collections2

As we can see, this approach is fairly similar to the one followed in the last section:

public Collection findEvenNumbers(Collection baseCollection) { Predicate guavaPredicate = item -> item % 2 == 0; return Collections2.filter(baseCollection, guavaPredicate); }

Again, here we define a Guava specific Predicate object.

In this case, Guava doesn't modify the baseCollection, it generates a new one, so we can use an immutable collection as input.

6. Conclusion

In summary, we've seen that there are many different ways of filtering collections in Java.

Even though Streams are usually the preferred approach, its good to know and keep in mind the functionality offered by other libraries.

Especially if we need to support older Java versions. However, if this is the case, we need to keep in mind recent Java features used throughout the tutorial such as lambdas should be replaced with anonymous classes.

Както обикновено, можем да намерим всички примери, показани в този урок, в нашето репо Github.