Predicado en Java

100

Estoy revisando el código que se usa Predicateen Java. Nunca lo he usado Predicate. ¿Alguien puede guiarme a algún tutorial o explicación conceptual Predicatey su implementación en Java?

srikanth
fuente
4
¿Estás hablando de Guayaba Predicate? ¿Algo parecido? ¿Algo completamente diferente?
polygenelubricants
2
También hay Apache CommonsPredicate
Dan Gravell

Respuestas:

203

Supongo que estás hablando com.google.common.base.Predicate<T>de Guava.

Desde la API:

Determina un valor trueo falsepara una entrada determinada. Por ejemplo, a RegexPredicatepodría implementar Predicate<String>y devolver verdadero para cualquier cadena que coincida con su expresión regular dada.

Esto es esencialmente una abstracción OOP para una booleanprueba.

Por ejemplo, puede tener un método auxiliar como este:

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

Ahora, dado un List<Integer>, puede procesar solo los números pares como este:

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

Con Predicate, la ifprueba se abstrae como un tipo. Esto le permite interoperar con el resto de la API, por ejemplo Iterables, que tiene muchos métodos de utilidad que toma Predicate.

Por lo tanto, ahora puede escribir algo como esto:

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

Tenga en cuenta que ahora el ciclo for-each es mucho más simple sin la ifprueba. Hemos alcanzado un nivel más alto de abtracción al definir Iterable<Integer> evenNumbers, al filterutilizar un Predicate.

Enlaces API


En función de orden superior

Predicatepermite Iterables.filterservir como lo que se llama una función de orden superior. Por sí solo, esto ofrece muchas ventajas. Tome el List<Integer> numbersejemplo anterior. Supongamos que queremos probar si todos los números son positivos. Podemos escribir algo como esto:

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

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

Con a Predicate, e interoperando con el resto de las bibliotecas, podemos escribir esto:

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

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

Es de esperar que ahora pueda ver el valor en abstracciones más altas para rutinas como "filtrar todos los elementos por el predicado dado", "comprobar si todos los elementos satisfacen el predicado dado", etc. para mejorar el código.

Desafortunadamente, Java no tiene métodos de primera clase: no puede pasar métodos a Iterables.filtery Iterables.all. Por supuesto, puede pasar objetos en Java. Por lo tanto, el Predicatetipo está definido y, en su lugar, pasa objetos que implementan esta interfaz.

Ver también

poligenelubricantes
fuente
4
No me refería al predicado de Guava, debería haber sido claro en mi pregunta, pero su explicación me ayudó a entender lo que estaba buscando, la forma en que se usa la lógica de predicados en Java. Gracias por la explicación elaborada
srikanth
@polygenelubricants, ¿Por qué inventar Predicate<Integer>cuando ya tenemos F<Integer, Boolean>cuál hace exactamente lo mismo?
Pacerier
También puede hacerlo a la manera 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 predicado es una función que devuelve un valor verdadero / falso (es decir, booleano), a diferencia de una proposición que es un valor verdadero / falso (es decir, booleano). En Java, no se pueden tener funciones independientes, por lo que se crea un predicado creando una interfaz para un objeto que representa un predicado y luego se proporciona una clase que implementa esa interfaz. Un ejemplo de una interfaz para un predicado podría ser:

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

Y luego podría tener una implementación como:

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

Para obtener una mejor comprensión conceptual, es posible que desee leer sobre lógica de primer orden.

Editar
Existe una interfaz Predicate estándar ( java.util.function.Predicate ) definida en la API de Java a partir de Java 8. Antes de Java 8, puede que le resulte conveniente reutilizar la interfaz com.google.common.base.Predicate de Guayaba .

Además, tenga en cuenta que a partir de Java 8, es mucho más sencillo escribir predicados utilizando lambdas. Por ejemplo, en Java 8 y superior, se puede pasar p -> truea una función en lugar de definir una subclase de Tautología con nombre como la anterior.

Michael Aaron Safyan
fuente
0

Puede ver los ejemplos de java doc o el ejemplo de uso de Predicate aquí

Básicamente, se utiliza para filtrar filas en el conjunto de resultados en función de cualquier criterio específico que pueda tener y devolver verdadero para aquellas filas que cumplen con sus criterios:

 // 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
fuente
Me refería al predicado commons, no al conjunto de resultados relacionado. gracias aunque
srikanth
0

Añadiendo a lo que ha dicho Micheal :

Puede usar Predicate de la siguiente manera en el filtrado de colecciones 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 posible predicado puede ser:

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

Uso:

 final List<DisplayFieldDto> filteredList=
 (List<DisplayFieldDto>)filter(displayFieldsList, filterCriteria);
jai
fuente
1
¿No derrota eso básicamente el propósito? La razón principal para elegir un enfoque funcional es NO iterar manualmente y deshacerse del for. El nivel de abstracción se vuelve más alto y más poderoso; sin embargo, hacer el for manualmente anula ese propósito y vuelve a la abstracción de bajo nivel.
Eugen