Подтвердить что ты не робот

Есть ли удобный метод для создания Predicate, который проверяет, соответствует ли поле заданному значению?

Мне часто приходится фильтровать Stream или использовать предикат, который проверяет, имеет ли данное поле заданное значение.

Скажем, например, у меня это POJO:

public class A {
    private Integer field;

    public A(final Integer field) {
        this.field = field;
    }

    public Integer getField() {
        return field;
    }
}

И я хочу отфильтровать объекты Stream на основе значения field:

    final Integer someValue = 42;
    Stream.of(new A(42), new A(1729), new A(42), new A(87539319), new A(null))
            .filter(a -> Objects.equals(a.getField(), someValue))
            ...

Будет ли метод удобства генерировать предикат для метода filter? Я заметил, что есть Predicate.isEqual, но это не соответствует потребностям.

Я мог бы легко написать одно вот так:

public static <T,R> Predicate<T> isEqual(Function<? super T, ? extends R> f, R value) {
    return v -> Objects.equals(value, f.apply(v));
}

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

    Stream.of(new A(42), new A(1729), new A(42), new A(87539319), new A(null))
            .filter(isEqual(A::getField, someValue))
            ...

но я предпочел бы повторно использовать существующий метод из JDK, если это возможно.

4b9b3361

Ответ 1

Нет такого встроенного метода factory, который вы можете легко проверить, просмотрев все использования Predicate в JFC и найдите "Методы в..., которые возвращают Предикат". Помимо методов внутри Predicate, существует только Pattern.asPredicate(), который возвращает Predicate.

Прежде чем вы начнете внедрять такой метод factory, вы должны спросить себя, действительно ли это стоит. То, что делает ваше лямбда-выражение в .filter(a -> Objects.equals(a.getField(), someValue)) сложным, - это использование Objects.equals, которое не требуется, если вы можете предсказать хотя бы один аргумент, является ли это null. Поскольку здесь someValue никогда не null, вы можете упростить выражение:

final Integer someValue = 42;
Stream.of(new A(42), new A(1729), new A(42), new A(87539319), new A(null))
    .filter(a -> someValue.equals(a.getField()))
    …

Если вы все еще хотите реализовать метод factory и выиграть цену за творческое использование того, что уже существует, вы можете использовать:

public static <T,R> Predicate<T> isEqual(Function<? super T, ? extends R> f, R value) {
    return f.andThen(Predicate.isEqual(value)::test)::apply;
}

Однако для производственного кода Id скорее рекомендую реализацию следующим образом:

public static <T,R> Predicate<T> isEqual(Function<? super T, ? extends R> f, R value) {
    return value==null? t -> f.apply(t)==null: t -> value.equals(f.apply(t));
}

Это заставляет проверить, является ли константа null, чтобы упростить операцию, которая будет выполняться в каждом тесте. Так что ему все равно не нужно Objects.equals. Обратите внимание, что Predicate.isEqual делает подобное.