Prédicat en Java

100

Je suis en train de parcourir le code qui utilise Predicateen Java. Je ne l'ai jamais utilisé Predicate. Quelqu'un peut-il me guider vers un didacticiel ou une explication conceptuelle Predicateet sa mise en œuvre en Java?

srikanth
la source
4
Parlez-vous de Guava Predicate? Quelque chose de similaire? Quelque chose de complètement différent?
polygenelubricants
2
Il y a aussi Apache CommonsPredicate
Dan Gravell

Réponses:

203

Je suppose que vous parlez com.google.common.base.Predicate<T>de Guava.

Depuis l'API:

Détermine une valeur trueou falsepour une entrée donnée. Par exemple, a RegexPredicatepourrait implémenter Predicate<String>et retourner true pour toute chaîne qui correspond à son expression régulière donnée.

Il s'agit essentiellement d'une abstraction POO pour un booleantest.

Par exemple, vous pouvez avoir une méthode d'assistance comme celle-ci:

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

Maintenant, étant donné a List<Integer>, vous ne pouvez traiter que les nombres pairs comme ceci:

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

Avec Predicate, le iftest est extrait en tant que type. Cela lui permet d'interagir avec le reste de l'API, par exemple Iterables, qui a de nombreuses méthodes utilitaires qui prennentPredicate .

Ainsi, vous pouvez maintenant écrire quelque chose comme ceci:

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

Notez que maintenant la boucle for-each est beaucoup plus simple sans le iftest. Nous avons atteint un niveau d'abtraction plus élevé en définissant Iterable<Integer> evenNumbers, en filterutilisant un Predicate.

Liens API


Sur la fonction d'ordre supérieur

Predicatepermet Iterables.filterde servir de ce qu'on appelle une fonction d'ordre supérieur. En soi, cela présente de nombreux avantages. Prenons l' List<Integer> numbersexemple ci-dessus. Supposons que nous voulions tester si tous les nombres sont positifs. Nous pouvons écrire quelque chose comme ceci:

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

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

Avec a Predicate, et en interopérant avec le reste des bibliothèques, nous pouvons à la place écrire ceci:

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

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

J'espère que vous pouvez maintenant voir la valeur dans des abstractions plus élevées pour des routines comme "filtrer tous les éléments par le prédicat donné", "vérifier si tous les éléments satisfont au prédicat donné", etc. pour un meilleur code.

Malheureusement, Java n'a pas de méthodes de première classe: vous ne pouvez pas passer de méthodes à Iterables.filteret Iterables.all. Vous pouvez bien sûr faire circuler des objets en Java. Ainsi, le Predicatetype est défini et vous passez des objets implémentant cette interface à la place.

Voir également

lubrifiants polygènes
la source
4
Je ne faisais pas référence au prédicat de Guava, j'aurais dû être clair dans ma question, mais votre explication m'a aidé à comprendre ce que je cherchais, la façon dont la logique de prédicat est utilisée en java. Merci pour l'explication élaborée
srikanth
@polygenelubricants, pourquoi inventer Predicate<Integer>quand on a déjà F<Integer, Boolean>qui fait exactement la même chose?
Pacerier
Vous pouvez également le faire à la manière de 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

Un prédicat est une fonction qui renvoie une valeur vrai / faux (c'est-à-dire booléenne), par opposition à une proposition qui est une valeur vrai / faux (c'est-à-dire booléenne). En Java, on ne peut pas avoir de fonctions autonomes, et donc on crée un prédicat en créant une interface pour un objet qui représente un prédicat et on fournit ensuite une classe qui implémente cette interface. Un exemple d'interface pour un prédicat pourrait être:

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

Et puis vous pourriez avoir une implémentation telle que:

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

Pour obtenir une meilleure compréhension conceptuelle, vous voudrez peut-être en savoir plus sur la logique du premier ordre.

Edit
Il existe une interface Predicate standard ( java.util.function.Predicate ) définie dans l'API Java à partir de Java 8. Avant Java 8, vous pouvez trouver pratique de réutiliser l' interface com.google.common.base.Predicate depuis Goyave .

Notez également qu'à partir de Java 8, il est beaucoup plus simple d'écrire des prédicats à l'aide de lambdas. Par exemple, dans Java 8 et supérieur, on peut passer p -> trueà une fonction au lieu de définir une sous-classe Tautology nommée comme ci-dessus.

Michael Aaron Safyan
la source
0

Vous pouvez voir les exemples de documentation java ou l'exemple d'utilisation de Predicate ici

Fondamentalement, il est utilisé pour filtrer les lignes de l'ensemble de résultats en fonction de tous les critères spécifiques que vous pouvez avoir et renvoyer true pour les lignes qui répondent à vos critères:

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

    // set the filter.
    resultset.beforeFirst();
    resultset.setFilter(filter);
techzen
la source
Je faisais référence au prédicat commun, pas au Resultset lié. merci bien
srikanth
0

Ajoutant à ce que Micheal a dit:

Vous pouvez utiliser Predicate comme suit pour filtrer les collections en 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;
}

un prédicat possible peut être:

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

Usage:

 final List<DisplayFieldDto> filteredList=
 (List<DisplayFieldDto>)filter(displayFieldsList, filterCriteria);
I have
la source
1
Cela ne va-t-il pas fondamentalement à l'encontre de l'objectif? La raison principale du choix d'une approche fonctionnelle est de NE PAS itérer manuellement et de se débarrasser du for. Le niveau d'abstraction devient plus élevé et plus puissant - cependant, le fait de le faire manuellement vainc cet objectif et revient à l'abstraction de bas niveau.
Eugen