Predykat w Javie


101

Przechodzę przez kod, który używa Predicatew Javie. Nigdy nie używałem Predicate. Czy ktoś może poprowadzić mnie do dowolnego samouczka lub wyjaśnienia koncepcyjnego Predicatei jego implementacji w Javie?


4
Mówisz o guawie Predicate? Coś podobnego? Coś zupełnie innego?
polygenelubricants

2
Jest też Apache CommonsPredicate
Dan Gravell

Odpowiedzi:


203

Zakładam, że mówisz o com.google.common.base.Predicate<T>Guava.

Z API:

Określa wartość truelub falsedla danego wejścia. Na przykład RegexPredicatemoże zaimplementować Predicate<String>i zwrócić wartość true dla dowolnego ciągu, który pasuje do danego wyrażenia regularnego.

Jest to w zasadzie abstrakcja OOP dla booleantestu.

Na przykład możesz mieć metodę pomocniczą, taką jak ta:

static boolean isEven(int num) {
   return (num % 2) == 0; // simple
}

Teraz, biorąc pod uwagę a List<Integer>, możesz przetwarzać tylko liczby parzyste w ten sposób:

    List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
    for (int number : numbers) {
        if (isEven(number)) {
            process(number);
        }
    }

W Predicateprzypadku iftest jest wyodrębniany jako typ. Pozwala to na współdziałanie z resztą API, na przykład Iterables, które mają wiele metod użytkowych Predicate.

Możesz więc teraz napisać coś takiego:

    Predicate<Integer> isEven = new Predicate<Integer>() {
        @Override public boolean apply(Integer number) {
            return (number % 2) == 0;
        }               
    };
    Iterable<Integer> evenNumbers = Iterables.filter(numbers, isEven);

    for (int number : evenNumbers) {
        process(number);
    }

Zauważ, że teraz pętla for-each jest znacznie prostsza bez iftestu. Osiągnęliśmy wyższy poziom abtraction, definiując Iterable<Integer> evenNumbers, filterużywając -a Predicate.

Linki API


Na funkcji wyższego rzędu

Predicatepozwala Iterables.filterpełnić funkcję tzw. funkcji wyższego rzędu. Samo w sobie ma to wiele zalet. Weź List<Integer> numberspowyższy przykład. Załóżmy, że chcemy sprawdzić, czy wszystkie liczby są dodatnie. Możemy napisać coś takiego:

static boolean isAllPositive(Iterable<Integer> numbers) {
    for (Integer number : numbers) {
        if (number < 0) {
            return false;
        }
    }
    return true;
}

//...
if (isAllPositive(numbers)) {
    System.out.println("Yep!");
}

Za pomocą Predicatei współpracując z pozostałymi bibliotekami możemy zamiast tego napisać:

Predicate<Integer> isPositive = new Predicate<Integer>() {
    @Override public boolean apply(Integer number) {
        return number > 0;
    }       
};

//...
if (Iterables.all(numbers, isPositive)) {
    System.out.println("Yep!");
}

Miejmy nadzieję, że teraz możesz zobaczyć wartość w wyższych abstrakcji dla procedur takich jak „filtruj wszystkie elementy według podanego predykatu”, „sprawdź, czy wszystkie elementy spełniają podany predykat”, itp. Tworzą lepszy kod.

Niestety Java nie ma metod pierwszej klasy: nie można przekazywać metod do Iterables.filteri Iterables.all. Możesz oczywiście przekazywać obiekty w Javie. W ten sposób Predicatetyp jest zdefiniowany i zamiast tego przekazujesz obiekty implementujące ten interfejs.

Zobacz też


4
Nie odnosiłem się do Predykatu Guawy, powinienem być jasny w moim pytaniu, ale Twoje wyjaśnienie pomogło mi zrozumieć, czego szukałem, w jaki sposób logika predykatów jest używana w Javie. Dziękuję za szczegółowe wyjaśnienie
srikanth

@polygenelubricants, Predicate<Integer>Po co wymyślać, skoro już mamy, F<Integer, Boolean>który robi dokładnie to samo?
Pacerier

Możesz to również zrobić w sposób java 8: List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Predicate<Integer> isEven = integer -> (integer % 2) == 0; Iterable<Integer> evenNumbers = numbers.stream().filter(isEven).collect(Collectors.toList());

14

Predykat to funkcja, która zwraca wartość prawda / fałsz (tj. Wartość logiczna), w przeciwieństwie do zdania, które jest wartością prawda / fałsz (tj. Wartość logiczną). W Javie nie można mieć samodzielnych funkcji, więc tworzy się predykat, tworząc interfejs dla obiektu, który reprezentuje predykat, a następnie udostępnia klasę, która implementuje ten interfejs. Przykładem interfejsu predykatu może być:

public interface Predicate<ARGTYPE>
{
    public boolean evaluate(ARGTYPE arg);
}

A potem możesz mieć implementację taką jak:

public class Tautology<E> implements Predicate<E>
{
     public boolean evaluate(E arg){
         return true;
     }
}

Aby lepiej zrozumieć koncepcję, możesz przeczytać o logice pierwszego rzędu.

Edycja
Istnieje standardowy interfejs predykatu ( java.util.function.Predicate ) zdefiniowany w Java API od wersji Java 8. Przed wersją Java 8 wygodnym może być ponowne użycie interfejsu com.google.common.base.Predicate z Guawa .

Należy również zauważyć, że od wersji Java 8 pisanie predykatów przy użyciu lambd jest znacznie prostsze. Na przykład w Javie 8 i nowszych można przejść p -> truedo funkcji zamiast definiować nazwaną podklasę Tautology, jak powyżej.


0

Możesz zobaczyć przykłady dokumentacji java lub przykład użycia Predicate tutaj

Zasadniczo służy do filtrowania wierszy w zestawie wyników na podstawie dowolnych określonych kryteriów i zwracania wartości true dla tych wierszy, które spełniają kryteria:

 // the age column to be between 7 and 10
    AgeFilter filter = new AgeFilter(7, 10, 3);

    // set the filter.
    resultset.beforeFirst();
    resultset.setFilter(filter);

Odnosiłem się do predykatu wspólnego, a nie do zbioru wyników. dzięki
srikanth

0

Podsumowując to, co powiedział Micheal :

Możesz użyć Predicate w następujący sposób do filtrowania kolekcji w java:

public static <T> Collection<T> filter(final Collection<T> target,
   final Predicate<T> predicate) {
  final Collection<T> result = new ArrayList<T>();
  for (final T element : target) {
   if (predicate.apply(element)) {
    result.add(element);
   }
  }
  return result;
}

jednym możliwym predykatem może być:

final Predicate<DisplayFieldDto> filterCriteria = 
                    new Predicate<DisplayFieldDto>() {
   public boolean apply(final DisplayFieldDto displayFieldDto) {
    return displayFieldDto.isDisplay();
   }
  };

Stosowanie:

 final List<DisplayFieldDto> filteredList=
 (List<DisplayFieldDto>)filter(displayFieldsList, filterCriteria);

1
Czy to w zasadzie nie podważa celu? Głównym powodem wyboru podejścia funkcjonalnego jest NIE iteracja ręcznie i pozbycie się for. Poziom abstrakcji staje się wyższy i potężniejszy - jednak ręczne wykonanie for mija się z tym celem i wraca do abstrakcji niskiego poziomu.
Eugen
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.