Рубрики
Без рубрики

Цепочка предикатов Java 8

Изучите различные способы связывания предикатов в Java

Автор оригинала: baeldung.

1. Обзор

В этом кратком руководстве мы обсудим различные способы цепочки Предикатов в Java 8.

2. Основной Пример

Во-первых, давайте посмотрим, как использовать простой Предикат для фильтрации Списка имен:

@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"));
}

В этом примере мы отфильтровали наш Список имен, чтобы оставить только имена, начинающиеся с “A”, используя предикат |:

name -> name.startsWith("A")

Но что, если бы мы хотели применить несколько Предикатов ?

3. Несколько Фильтров

Если мы хотим применить несколько Предикатов , один из вариантов – просто связать несколько фильтров в цепочку:

@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"));
}

Теперь мы обновили наш пример, чтобы отфильтровать наш список, извлекая имена, которые начинаются с “А” и имеют длину менее 5.

Мы использовали два фильтра — по одному для каждого предиката .

4. Сложный предикат

Теперь вместо использования нескольких фильтров мы можем использовать один фильтр со сложным предикатом :

@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"));
}

Этот вариант более гибкий, чем первый, так как мы можем использовать побитовые операции для построения предиката настолько сложного, насколько мы хотим.

5. Объединение предикатов

Далее, если мы не хотим создавать сложный Предикат с использованием побитовых операций, Java 8 Предикат имеет полезные методы, которые мы можем использовать для объединения Предикатов .

Мы объединим Предикаты использование методов Предикат.и() , Предикат.или() , и Предикат.negate().

5.1. Предикат.и()

В этом примере мы определим наши Предикаты явно, а затем объединим их с помощью Предиката.():

@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"));
}

Как мы видим, синтаксис довольно интуитивно понятен, а имена методов указывают на тип операции. Используя и() , мы отфильтровали List , извлекая только имена, которые удовлетворяют обоим условиям.

5.2. Предикат.или()

Мы также можем использовать Предикат.или() для объединения Предикатов.

Давайте извлекем имена, начинающиеся с “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() при объединении наших Предикатов :

@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"));
}

Здесь мы использовали комбинацию или() и negate() для фильтрации Списка по именам, которые начинаются с “J” или имеют длину не менее 4.

5.4. Объединение предикатов в ряд

Нам не нужно явно определять наши Предикаты для использования и (), | или () и отрицания().

Мы также можем использовать их встроенно, приведя предикат |:

@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. Объединение набора предикатов

Наконец, давайте посмотрим, как связать коллекцию Предикатов , сократив их.

В следующем примере у нас есть Список предикатов , которые мы объединили с помощью Предиката.и() :

@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

Но это будет по-другому, если мы захотим объединить их с помощью предиката.или() :

@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 (), building complex Predicates и комбинируя Предикаты.

Полный исходный код доступен на GitHub .