CodeGym /Blog Java /Poland /Predykaty Java z przykładami
Autor
Artem Divertitto
Senior Android Developer at United Tech

Predykaty Java z przykładami

Opublikowano w grupie Poland
Ogólnie predykat to wyrażenie, które określa, czy wartość może być prawdziwa lub fałszywa. W programowaniu predykaty to funkcje z jednym argumentem, które zwracają wartość boolean. Interfejs funkcyjny predykat został wprowadzony w Javie 8. "Funkcyjny" oznacza, że zawiera tylko jedną abstrakcyjną metodę. Przyjmuje ona argument i zwraca boolean. W Javie interfejsy funkcyjne są używane do obsługi wyrażeń Lambda oraz referencji do metod i konstruktorów. Zwykle predykat Java 8 służy do zastosowania filtru do kolekcji obiektów. Przyjrzyjmy się jego głównym zastosowaniom i szeroko stosowanym metodom oraz rozwiążmy niektóre problemy praktyczne.Predykaty Java z przykładami - 1

Dlaczego deweloperzy używają predykatów

Zasadniczo programiści mogą używać predykatów do dowolnych zadań, które obejmują ocenę elementów w oparciu o wstępnie zdefiniowane kryteria i zwracaną wartość logiczną. Oto przykłady prostych zadań, które programiści wykonują za pomocą predykatów:
  • Filtrowanie zbioru liczb całkowitych.
  • Sortowanie list poprzez zapewnienie zgodności danych z kilkoma predefiniowanymi warunkami (np. uporządkowanie grupy elementów przez ustalenie warunków cenowych i wagowych).
  • Używanie pakietów narzędziowych w programowaniu współbieżnym.
Predykaty są ważną funkcją w testowaniu oprogramowania. Interfejsy funkcyjne ułatwiają oddzielanie jednostek do testowania, poprawiają czytelność i łatwość zarządzania kodem aplikacji.

Składnia predykatu w Javie

Interfejs java.util.function.Predicate został wprowadzony w Javie 8 jako alternatywny sposób na obsługę oceny wyświetleń w Lambdzie. Standardowy widok interfejsu to Predicate<T>, gdzie T jest pojedynczym argumentem zwracającym wartość logiczną. Predykat Java ma funkcyjną (abstrakcyjną) metodę test(Object), która ocenia predykat dla wskazanego obiektu.

@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
Oto przykład prostego predykatu, który filtruje liczby całkowite na podstawie warunków "większe niż", "mniejsze niż".

// An example of a simple Java predicate
  
import java.util.function.Predicate; 
public class PredicateExample { 
    public static void main(String[] args) 
    { 
        // Creating predicate 
        Predicate<Integer> lesserThan = i -> (i < 18);  
  
        // Calling Predicate method 
        System.out.println(lesserThan.test(10));  
    }
}
Wynikiem będzie true ponieważ 10 < 18. Jeszcze jeden przykład z predykatem w filter(). Predykat pomaga odfiltrować wszystkich dorosłych z listy wiekowej.

  import java.util.List;
  import java.util.function.Predicate;

  public class PredicateExample {
      public static void main(String[] args) {
          List<Integer> ages = List.of(17, 18, 19, 28, 18, 28, 46, 7, 8, 9, 21, 12);
          NotLessThan18<Integer> isAdult = new NotLessThan18<>();
          ages.stream().filter(isAdult).forEach(System.out::println);
      }
  }



class NotLessThan18<E> implements Predicate<Integer> {

      @Override
      public boolean test(Integer v) {
          Integer ADULT = 18;
          return v >= ADULT;
      }
  }
Wyświetlone zostanie:
18 19 28 18 28 46 21

Metody predykatów w Java 8

Interfejs Predykat udostępnia kilka metod.
  • boolean test(T t) ocenia predykat dla wskazanego argumentu.
  • default Predicate<T> and(Predicate<? super T> other) zwraca predykat, który reprezentuje połączenie logiczne (AND) tego i innego predykatu.
  • default Predicate<T> or zwraca predykat, który reprezentuje połączenie logiczne (OR) tego i innego predykatu.
  • default Predicate<T> negate() zwraca predykat, który jest logicznym przeciwieństwem tego predykatu.
  • default Predicate<T> isEqual(Object targetRef) zwraca wynik testu sprawdzającego, czy dwa argumenty są sobie równe zgodnie z Objects.equals(Object, Object).

boolean test(T t)

Jest to metoda funkcyjna dla predykatów Java, która ocenia, czy dany argument spełnia warunek predykatu. Przykład: tworzymy predykat adult dla każdego kto ma 18 lat lub więcej. Metoda test() pobiera wartość całkowitą i sprawdza ją.

import java.util.function.Predicate;
public class PredicateTestTest {
   public static void main(String[] args) {
       Predicate<Integer> adult = i -> i >= 18;
       System.out.println(adult.test(12));
       System.out.println(adult.test(19));
       System.out.println(adult.test(21));
   }
}
Jaki będzie wynik dla powyższego kodu? W pierwszym przypadku, ponieważ 12 jest mniejsze niż 18, będzie to false. W drugim i trzecim scenariuszu warunki są spełnione, zatem zwrócone zostanie true.
false true true

default Predicate.and()

Ta metoda reprezentuje operator "and". Dlatego jeśli jeden z wskazanych predykatów nie spełnia zadanego warunku, drugi nie będzie sprawdzany. Przykład: Stwórzmy za pomocą and() predykaty Java, które filtrują wszystkie dorosłe osoby, które jednocześnie mają mniej niż 65 lat. Użyjmy predicate.add () i napiszmy predykat Java z lambdą dla tych warunków: Jeżeli warunek jest spełniony, aplikacja zwróci następujące wyrażenie:

import java.util.function.Predicate;

   public class PredicateDemo {
       public static void main(String[] args) {
           Predicate<Integer> adultYet = i -> i >= 18;
           Predicate<Integer> adultStill = i -> i < 65;
           System.out.println(adultYet.and(adultStill).test(5));
           System.out.println(adultYet.and(adultStill).test(38));
           System.out.println(adultYet.and(adultStill).test(90));
       }
   }
Wyświetlone zostanie:
false true false

default Predicate.or()

Metoda Predicate.or() reprezentuje operator "OR". Oznacza to, że warunek zostanie spełniony nawet jeśli tylko jeden z predykatów zwróci wartość true, a drugi false. Przykład: oceńmy ciągi znaków. Spróbuj użyć metody OR, aby wybrać wszystkie frazy zawierające podciąg "moja" lub "kredka".

import java.util.function.Predicate;

  public class PredicateDemo2 {
      public static void main(String[] args) {
          Predicate<String> containsA = t -> t.contains("crayon");
          Predicate<String> containsB = t -> t.contains("my");
          System.out.println(containsA.or(containsB).test("here is my crayon"));
          System.out.println(containsA.or(containsB).test("here is my pencil"));
          System.out.println(containsA.or(containsB).test("here is John's crayon"));
          System.out.println(containsA.or(containsB).test("here is John's pencil"));
      }
  }
Wyświetlone zostanie:
true true true false

default Predicate negate()

Metoda negate() służy do zbierania wszystkich wartości, które nie spełniają wcześniej zdefiniowanych kryteriów. Przykład: jeśli chcesz posortować klasę "Tomatoes" i znaleźć wpisy, które nie są "Red", możesz napisać predykat i szybko przeskanować całą sekwencję. Spróbuj samodzielnie napisać kod tego predykatu i porównaj jego wynik z rozwiązaniem.

import java.util.function.Predicate;

public class PredicateDemo3 {
public static void main(String[] args) {
 Predicate<Integer> adult = i -> i >= 18;
System.out.println(adult.negate().test(7));  System.out.println(adult.negate().test(19))
  }
   }
Wyświetlone zostanie:
true false

static Predicate isEqual(Object targetRef)

Ta metoda jest bardzo przydatna, jeżeli chcesz sprawdzić, czy dwa obiekty są równe wartości zdefiniowanej jako parametr Objects.equals(). Ta metoda jest szczególnie przydatna, jeśli chcesz porównać podobne wyniki testów. Przykład: powiedzmy, że porównujesz dwa wózki z gruszkami i chcesz sprawdzić, czy oba zawierają owoce i standardowej wadze i kolorze. W tym przypadku static Predicate isEqual(Object targetRef) jest dokładnie tą metodą której potrzebujesz. Przyjrzyjmy się, jak isEqual sprawdza równość dwóch ciągów:

import java.util.function.Predicate;

public class PredicateDemo2 {
   public static void main(String[] args) {
       Predicate<String> i = Predicate.isEqual("here is my crayon");
       System.out.println(i.test("here is my pencil"));
       System.out.println(i.test("here is my crayon"));
   }
}
Jeżeli analizowany obiekt spełnia standardowe warunki, funkcja zwróci true. Wyświetlone zostanie:
false true
Predykaty Java z przykładami - 2

IntPredicate w Javie

IntPredicate to interfejs funkcyjny, zatem możesz użyć go jako cel przypisania w wyrażeniu lambda lub referencja do metody. IntPredicate operuje na liczbie całkowitej i zwraca wartość predykatu na podstawie warunku. Tak jak interfejs Predicate, IntPredicate również posiada metody test(), and(), negate(), or(). Oto przykład IntPredicate. Wybiera on z tablicy wszystkich dorosłych (18 lub więcej).

import java.util.Arrays;
import java.util.function.IntPredicate;

public class IntPredicateExample {

   public static void main(String[] args) {

       int[] ages = { 18, 28, 18, 46, 90, 45, 2, 3, 1, 5, 7, 21, 12 };

       IntPredicate p = n -> n >= 18;

       Arrays.stream(ages).filter(p).forEach(System.out::println);
   }
}
Wyświetlone zostanie:
18 28 18 46 90 45 21

Pisanie czystych predykatów w Javie

Predykaty Java są bardzo funkcjonalne i przyjemnie się z nimi pracuje. Jednak jeśli nie masz świadomości, jak tworzone wyrażenia lambda wpływają na Twój kod, istnieje ryzyko, że kod stanie się trudny w utrzymaniu przez niechlujne predykaty. Oto kilka prostych praktyk, które sprawią, że Twoje interfejsy funkcyjne będą łatwe w zarządzaniu i czytaniu.
  • Nie powtarzaj się — nie twórz predykatów w Javie z powtarzającymi się wartościami, metodami i warunkami. W ten sposób marnujesz swój czas i sprawiasz, że kod jest zaśmiecony.
  • Oddzielaj predykaty od kodu aplikacji, aby zapewnić testowalność. Poza tym utwórz harmonogram testów jednostkowych predykatów i trzymaj się go.
  • Używaj importów i wzorców projektowych, aby mieć pewność, że Twoje klasy nie są rozdmuchane i będą łatwe w zarządzaniu.
  • Rozważ przeniesienie predykatów Java do klas typu Helper — poprawisz przez to możliwość ponownego wykorzystania kodu i ułatwisz jego utrzymanie.
  • Czytelność — gdy tylko jest to możliwe, preferuj instrukcje jednowierszowe zamiast złożonych predykatów. Może być kuszące, aby pochwalić się zrozumieniem złożonych interfejsów funkcyjnych. Jednak jeśli chodzi o utrzymywanie kodu, mniej znaczy więcej.
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION