1. Обзор
В этом кратком руководстве мы обсудим различные способы цепочки Предикатов в Java 8.
2. Основной Пример
Во-первых, давайте посмотрим, как использовать простой Предикат для фильтрации Списка имен:
@Test public void whenFilterList_thenSuccess(){ Listnames = 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")); }
В этом примере мы отфильтровали наш Список имен, чтобы оставить только имена, начинающиеся с “A”, используя предикат |:
name -> name.startsWith("A")
Но что, если бы мы хотели применить несколько Предикатов ?
3. Несколько Фильтров
Если мы хотим применить несколько Предикатов , один из вариантов – просто связать несколько фильтров в цепочку:
@Test public void whenFilterListWithMultipleFilters_thenSuccess(){ Listresult = names.stream() .filter(name -> name.startsWith("A")) .filter(name -> name.length() < 5) .collect(Collectors.toList()); assertEquals(1, result.size()); assertThat(result, contains("Adam")); }
Теперь мы обновили наш пример, чтобы отфильтровать наш список, извлекая имена, которые начинаются с “А” и имеют длину менее 5.
Мы использовали два фильтра — по одному для каждого предиката .
4. Сложный предикат
Теперь вместо использования нескольких фильтров мы можем использовать один фильтр со сложным предикатом :
@Test public void whenFilterListWithComplexPredicate_thenSuccess(){ Listresult = names.stream() .filter(name -> name.startsWith("A") && name.length() < 5) .collect(Collectors.toList()); assertEquals(1, result.size()); assertThat(result, contains("Adam")); }
Этот вариант более гибкий, чем первый, так как мы можем использовать побитовые операции для построения предиката настолько сложного, насколько мы хотим.
5. Объединение предикатов
Далее, если мы не хотим создавать сложный Предикат с использованием побитовых операций, Java 8 Предикат имеет полезные методы, которые мы можем использовать для объединения Предикатов .
Мы объединим Предикаты использование методов Предикат.и() , Предикат.или() , и Предикат.negate().
5.1. Предикат.и()
В этом примере мы определим наши Предикаты явно, а затем объединим их с помощью Предиката.():
@Test public void whenFilterListWithCombinedPredicatesUsingAnd_thenSuccess(){ Predicatepredicate1 = 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")); }
Как мы видим, синтаксис довольно интуитивно понятен, а имена методов указывают на тип операции. Используя и() , мы отфильтровали List , извлекая только имена, которые удовлетворяют обоим условиям.
5.2. Предикат.или()
Мы также можем использовать Предикат.или() для объединения Предикатов.
Давайте извлекем имена, начинающиеся с “J”, а также имена длиной менее 4:
@Test public void whenFilterListWithCombinedPredicatesUsingOr_thenSuccess(){ Predicatepredicate1 = 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() при объединении наших Предикатов :
@Test public void whenFilterListWithCombinedPredicatesUsingOrAndNegate_thenSuccess(){ Predicatepredicate1 = 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")); }
Здесь мы использовали комбинацию или() и negate() для фильтрации Списка по именам, которые начинаются с “J” или имеют длину не менее 4.
5.4. Объединение предикатов в ряд
Нам не нужно явно определять наши Предикаты для использования и (), | или () и отрицания().
Мы также можем использовать их встроенно, приведя предикат |:
@Test public void whenFilterListWithCombinedPredicatesInline_thenSuccess(){ Listresult = 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. Объединение набора предикатов
Наконец, давайте посмотрим, как связать коллекцию Предикатов , сократив их.
В следующем примере у нас есть Список предикатов , которые мы объединили с помощью Предиката.и() :
@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); Listresult = names.stream() .filter(allPredicates.stream().reduce(x->true, Predicate::and)) .collect(Collectors.toList()); assertEquals(1, result.size()); assertThat(result, contains("Alexander")); }
Обратите внимание, что мы используем нашу базовую идентичность в качестве:
x->true
Но это будет по-другому, если мы захотим объединить их с помощью предиката.или() :
@Test public void whenFilterListWithCollectionOfPredicatesUsingOr_thenSuccess(){ Listresult = 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 (), building complex Predicates и комбинируя Предикаты.
Полный исходный код доступен на GitHub .