Цепочка предикатов Java 8
1. обзор
В этом кратком руководствеwe’ll discuss different ways to chain Predicates in Java 8.
2. Основной пример
Во-первых,let’s see how to use a simple Predicate для фильтрацииList имен:
@Test
public void whenFilterList_thenSuccess(){
List names = Arrays.asList("Adam", "Alexander", "John", "Tom");
List result = names.stream()
.filter(name -> name.startsWith("A"))
.collect(Collectors.toList());
assertEquals(2, result.size());
assertThat(result, contains("Adam","Alexander"));
}
В этом примере мы отфильтровали нашиList имен, чтобы оставить только имена, начинающиеся с «A», используяPredicate:
name -> name.startsWith("A")
Но что, если бы мы хотели применить несколькоPredicates?
3. Несколько фильтров
Если бы мы хотели применить несколькоPredicates,one option is to simply chain multiple filters:
@Test
public void whenFilterListWithMultipleFilters_thenSuccess(){
List result = names.stream()
.filter(name -> name.startsWith("A"))
.filter(name -> name.length() < 5)
.collect(Collectors.toList());
assertEquals(1, result.size());
assertThat(result, contains("Adam"));
}
Мы обновили наш пример, чтобы отфильтровать список, извлекая имена, начинающиеся с буквы «A» и имеющие длину меньше 5.
Мы использовали два фильтра - по одному на каждыйPredicate.
4. КомплексPredicate
Теперь вместо использования нескольких фильтровwe can use one filter with a complex Predicate:
@Test
public void whenFilterListWithComplexPredicate_thenSuccess(){
List result = names.stream()
.filter(name -> name.startsWith("A") && name.length() < 5)
.collect(Collectors.toList());
assertEquals(1, result.size());
assertThat(result, contains("Adam"));
}
Этот вариант более гибкий, чем первый, посколькуwe can use bitwise operations to build the Predicate настолько сложен, насколько мы хотим.
5. ОбъединениеPredicates
Далее, если мы не хотим строить сложныйPredicate с помощью побитовых операций, в Java 8Predicate есть полезные методы, которые мы можем использовать для объединенияPredicates.
Мы объединимPredicates, используя методыPredicate.and(),Predicate.or() иPredicate.negate().
5.1. Predicate.and()с
В этом примере мы явно определим нашиPredicates, а затем объединим их, используяPredicate.and():
@Test
public void whenFilterListWithCombinedPredicatesUsingAnd_thenSuccess(){
Predicate predicate1 = str -> str.startsWith("A");
Predicate predicate2 = str -> str.length() < 5;
List result = names.stream()
.filter(predicate1.and(predicate2))
.collect(Collectors.toList());
assertEquals(1, result.size());
assertThat(result, contains("Adam"));
}
Как мы видим, синтаксис довольно интуитивен, а имена методов указывают на тип операции. Используяand(), мы отфильтровали нашList, извлекая только имена, которые удовлетворяют обоим условиям.
5.2. Predicate.or()с
Мы также можем использоватьPredicate.or() для объединенияPredicates.
Давайте извлечем имена, начинающиеся с буквы «J», а также имена, длина которых меньше 4:
@Test
public void whenFilterListWithCombinedPredicatesUsingOr_thenSuccess(){
Predicate predicate1 = str -> str.startsWith("J");
Predicate predicate2 = str -> str.length() < 4;
List result = names.stream()
.filter(predicate1.or(predicate2))
.collect(Collectors.toList());
assertEquals(2, result.size());
assertThat(result, contains("John","Tom"));
}
5.3. Predicate.negate()с
Мы также можем использоватьPredicate.negate() при объединении нашихPredicates:
@Test
public void whenFilterListWithCombinedPredicatesUsingOrAndNegate_thenSuccess(){
Predicate predicate1 = str -> str.startsWith("J");
Predicate predicate2 = str -> str.length() < 4;
List result = names.stream()
.filter(predicate1.or(predicate2.negate()))
.collect(Collectors.toList());
assertEquals(3, result.size());
assertThat(result, contains("Adam","Alexander","John"));
}
Здесь мы использовали комбинациюor() иnegate(), чтобы отфильтроватьList по именам, которые начинаются с «J» или имеют длину не менее 4.
5.4. ОбъединитьPredicates Inline
Нам не нужно явно определять нашPredicates, чтобы использоватьand(),or() иnegate().
Мы также можем использовать их встроенными, приведяPredicate:
@Test
public void whenFilterListWithCombinedPredicatesInline_thenSuccess(){
List result = names.stream()
.filter(((Predicate)name -> name.startsWith("A"))
.and(name -> name.length()<5))
.collect(Collectors.toList());
assertEquals(1, result.size());
assertThat(result, contains("Adam"));
}
6. Объединение коллекцииPredicates
Наконец,let’s see how to chain a collection of Predicates by reducing them.
В следующем примере у нас естьList изPredicates, которые мы объединили с помощьюPredicate.and():
@Test
public void whenFilterListWithCollectionOfPredicatesUsingAnd_thenSuccess(){
List> allPredicates = new ArrayList>();
allPredicates.add(str -> str.startsWith("A"));
allPredicates.add(str -> str.contains("d"));
allPredicates.add(str -> str.length() > 4);
List result = names.stream()
.filter(allPredicates.stream().reduce(x->true, Predicate::and))
.collect(Collectors.toList());
assertEquals(1, result.size());
assertThat(result, contains("Alexander"));
}
Обратите внимание, что мы используем нашу базовую идентичность как:
x->true
Но все будет по-другому, если мы захотим объединить их с помощьюPredicate.or():
@Test
public void whenFilterListWithCollectionOfPredicatesUsingOr_thenSuccess(){
List result = names.stream()
.filter(allPredicates.stream().reduce(x->false, Predicate::or))
.collect(Collectors.toList());
assertEquals(2, result.size());
assertThat(result, contains("Adam","Alexander"));
}
7. Заключение
В этой статье мы изучили различные способы объединения предикатов в Java 8, используяfilter(),, строящий комплексPredicates и комбинируяPredicates.
Доступен полный исходный кодover on GitHub.