Predicate
Predicate es una interfaz funcional que se encuentra en el paquete java.util.function. Mejora la capacidad de administración del código, ayuda a realizar pruebas unitarias por separado.
Se utiliza en expresiones lambda para comprobar si una condición dada es verdadera o falsa.
En lugar de pasar un booleano con valor true or false, pasas una referencia de tipo Predicate para determinar de manera dinámica si una condición dada es verdadera, o falsa.
Esta es la estructura de la interfaz Predicate:
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
Como vemos la interfaz Predicate utiliza los genéricos para poder decirle que tipo concreto vamos a utilizar.
Ejemplo:
public class EjemploPredicate {
public static void main(String[] args) {
Predicate<String> checker = a -> a.startsWith("M");
System.out.println(checker.test("Miguel"));
}
}
Hemos creado un objeto Predicate de tipo String. Le damos cuerpo al método test con una expresión lambda que se le pasa un argumento y devuelve un booleano.
Métodos Predicate
La interfaz Predicate contiene algunos métodos como:
isEqual(Object targetRef): Devuelve un predicado que prueba si dos argumentos son iguales.and(Predicate other): Devuelve un predicado compuesto que representa un AND lógico de este predicado y otro.or(Predicate other): Devuelve un predicado compuesto que representa un OR lógico de este predicado y otro.negate(): Devuelve un predicado que representa la negación lógica de este predicado.
Ejemplo:
Predicate<Integer> greaterThan10 = i -> i > 10;
Predicate<Integer> lessThan20 = i -> i < 20;
System.out.println(greaterThan10.and(lessThan20).test(15));
Predicate<Integer> greaterThanTen = (i) -> i > 10;
Predicate<Integer> lowerThanTwenty = (i) -> i < 20;
boolean resul = greaterThanTen.and(lowerThanTwenty).test(15);//true
boolean resul2 = greaterThanTen.and(lowerThanTwenty).negate().test(15);//false
Predicate<String> i = Predicate.isEqual("asdf");
System.out.println(i.test("java"));//false
Note
Debido al uso extendido de Predicate se han añadido las interfaces funcionales IntPredicate cuando queremos trabajar con predicados de tipo entero, DoublePredicate y LongPredicate. También tenemos la interfaz BiPredicate que es un caso especial de Predicate y recibe dos parámetros en vez de uno.
IntPredicate predicate = (x) -> {
if (x == 12345) {
return true;
}
return false;
};
System.out.println(predicate.test(12345));
IntPredicate intPredicate1 = predicate.negate();
System.out.println(intPredicate1.test(12345));
BiPredicate<String, Integer> filtroLongitud = (x, y) -> {
return x.length() == y;
};
boolean result = filter.test("java", 10);
System.out.println(result); // false
Supplier
Supplier es otra interfaz funcional dentro del paquete java.util.function que nos provee del método abstracto **get**, sin argumentos que devuelve un tipo de dato.
@FunctionalInterface
public interface Supplier<T> {
T get();
}
Esta interfaz también se utiliza con expresiones lambda que no tienen parámetros pero devuelven un resultado:
Random random = new Random();
Supplier<Integer> su = () -> random.nextInt();
Al igual que ocurría en los predicados con los Supplier también disponemos de las clases IntSupplier, DoubleSupplier, LongSupplier y BooleanSupplier.
Consumer
Consumer es otra interfaz funcional dentro del paquete java.util.function que provee un método que recibe un solo parámetro de tipo genérico y no devuelve nada.
public interface Consumer<T> {
void accept(T t);
}
La expresión lambda asignada a un objeto de tipo Consumer se usa para definir su método **accept(T t)** que eventualmente aplica la operación dada en su argumento. Los Consumer son útiles cuando no necesitan devolver ningún valor, ya que se espera que operen a través de efectos secundarios.
Existen también las interfaces IntConsumer, LongConsumer y DoubleConsumer.
Consumer<Integer> numero = (x) -> System.out.println(x);
numero.accept(5);
BiConsumer es un caso especial de las expresiones Consumer, son aquellas que reciben dos valores como parámetro y no devuelven resultado.
@FunctionalInterface
public interface BiConsumer<T, U> {
void accept(T t, U u);
}
Ejemplo:
BiConsumer<Integer, String> biConsumer = (x, s) -> System.out.println(x + s);
biConsumer.accept(3, " puntos");