Создать предикат с методами и/или/отменить в одном выражении?

java.util.function.Predicate имеет несколько полезных методов, таких как and, or и т. д., которые более лаконичны, чем создание оргии скобок с несколькими логическими операторами. К сожалению, похоже, что нет никакого способа использовать эти функции без явного наличия предиката...

Predicate<String> predicate = String::isEmpty;
Predicate<String> predicateWithAnd = predicate.and( MyClass::testSomething ); 

Есть ли способ создать 2-й предикат только в одном выражении (таким образом, «сохранив» переменную), например...

Predicate<String> predicateWithAnd = (String::isEmpty).and( MyClass::testSomething );  // That doesn't seem to work ;-)

Просто любопытно...


person Florian Schaetz    schedule 12.03.2016    source источник
comment
Пожалуйста, обратите внимание на это и это   -  person Holger    schedule 14.03.2016


Ответы (2)


Да, вам нужно привести свою лямбду к типу Predicate, где T — ваш тип. Пример с классом Person.

Predicate<Person> a = ((Predicate<Person>)p -> p.getId() > 2)
                                     .and(p -> p.getPrice() > 100);
person ByeBye    schedule 12.03.2016
comment
Спасибо. Пробовал, но, должно быть, сделал какую-то опечатку. К сожалению, с явным актерским составом он не такой короткий, как я надеялся, но, думаю, это цена. - person Florian Schaetz; 12.03.2016

Не очень понятно, почему str -> str.isEmpty() && MyClass.testSomething(str) называют "скобочной оргией". Это читабельно и коротко. В общем, эти and, or методы полезны, когда у вас есть готовые Predicate объекты. Их не следует использовать для объединения ссылок на методы или лямбда-выражений.

Если вы действительно хотите использовать ссылки на методы, есть несколько приемов. Во-первых, вы можете создать свой собственный служебный класс следующим образом:

import java.util.function.Predicate;
import java.util.stream.Stream;

public class Predicates {
    @SafeVarargs
    public static <T> Predicate<T> and(Predicate<T>... preds) {
        return Stream.of(preds).reduce(Predicate::and).orElse(x -> true);
    }

    @SafeVarargs
    public static <T> Predicate<T> or(Predicate<T>... preds) {
        return Stream.of(preds).reduce(Predicate::or).orElse(x -> false);
    }
}

И используйте это так:

import static mypackage.Predicates.*;

Predicate<String> predicateWithAnd = and(String::isEmpty, MyClass::testSomething);

В качестве альтернативы вы можете создать только один совершенно бесполезный статический метод:

public static <T> Predicate<T> pred(Predicate<T> pred) {
    return pred;
}

И используйте это так:

pred(String::isEmpty).and(MyClass::testSomething);

Это намного короче, чем явное приведение типов. Однако я бы по-прежнему рекомендовал оставаться с явной лямбдой, такой как str -> str.isEmpty() && MyClass.testSomething(str).

person Tagir Valeev    schedule 12.03.2016
comment
Нет, этот пример не будет оргией со скобками, а объединит еще несколько операторов со скобками, &&, || и !, то это происходит довольно быстро. - person Florian Schaetz; 12.03.2016
comment
@FlorianSchaetz, то же самое произойдет, если вы объедините их с сериями and, or, negate. Вам также понадобится несколько скобок. - person Tagir Valeev; 12.03.2016