Предикат в Java


101

Я просматриваю код, который используется Predicateв Java. Никогда не использовал Predicate. Может ли кто-нибудь направить меня к любому руководству или концептуальному объяснению Predicateи его реализации на Java?


4
Вы говорите о Гуаве Predicate? Что-то похожее? Что-то совсем другое?
polygenelubricants

2
Также есть Apache CommonsPredicate
Дэн Грейвелл

Ответы:


203

Я полагаю, вы говорите о com.google.common.base.Predicate<T>Гуаве.

Из API:

Определяет значение trueили falseдля заданного входа. Например, a RegexPredicateможет реализовать Predicate<String>и вернуть истину для любой строки, соответствующей данному регулярному выражению.

По сути, это абстракция ООП для booleanтеста.

Например, у вас может быть такой вспомогательный метод:

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

Теперь, учитывая a List<Integer>, вы можете обрабатывать только четные числа следующим образом:

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

С Predicate, то ifиспытание абстрагировано как тип. Это позволяет ему взаимодействовать с остальной частью API, например Iterables, который имеет много служебных методов, которые принимают Predicate.

Таким образом, теперь вы можете написать что-то вроде этого:

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

Обратите внимание, что теперь цикл for-each намного проще без ifтеста. Мы достигли более высокого уровня абстракции, определив Iterable<Integer> evenNumbers, filterиспользуя a Predicate.

Ссылки API

  • Iterables.filter
    • Возвращает элементы, удовлетворяющие предикату.

О функции высшего порядка

Predicateпозволяет Iterables.filterвыполнять функции так называемой функции высшего порядка. Само по себе это дает много преимуществ. Возьмите List<Integer> numbersпример выше. Предположим, мы хотим проверить, все ли числа положительны. Мы можем написать что-то вроде этого:

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

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

С помощью Predicateи, взаимодействуя с остальными библиотеками, мы можем вместо этого написать следующее:

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

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

Надеюсь, теперь вы можете видеть значение в более высоких абстракциях для таких подпрограмм, как «фильтровать все элементы по заданному предикату», «проверять, все ли элементы удовлетворяют заданному предикату» и т. Д., Чтобы улучшить код.

К сожалению, в Java нет первоклассных методов: вы не можете передавать методы в Iterables.filterи Iterables.all. Конечно, вы можете передавать объекты в Java. Таким образом, Predicateтип определен, и вместо него вы передаете объекты, реализующие этот интерфейс.

Смотрите также


4
Я не имел в виду предикат Guava, я должен был четко сформулировать свой вопрос, но ваше объяснение помогло мне понять, что я искал, как логика предикатов используется в java. Спасибо за подробное объяснение
srikanth

@polygenelubricants, зачем изобретать, Predicate<Integer>когда у нас уже есть то, F<Integer, Boolean>что делает то же самое?
Pacerier

Вы также можете сделать это с помощью 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

Предикат - это функция, которая возвращает истинное / ложное (то есть логическое) значение, в отличие от предложения, которое является истинным / ложным (то есть логическим) значением. В Java не может быть автономных функций, поэтому один создает предикат, создавая интерфейс для объекта, который представляет предикат, а затем предоставляет класс, реализующий этот интерфейс. Примером интерфейса для предиката может быть:

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

И тогда у вас может быть такая реализация, как:

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

Чтобы получить лучшее концептуальное понимание, вы можете прочитать о логике первого порядка.

Редактировать
Существует стандартный интерфейс Predicate ( java.util.function.Predicate ), определенный в Java API начиная с Java 8. До Java 8 вам может быть удобно повторно использовать интерфейс com.google.common.base.Predicate из Гуава .

Также обратите внимание, что начиная с Java 8 гораздо проще писать предикаты с использованием лямбда-выражений. Например, в Java 8 и выше можно перейти p -> trueк функции вместо определения именованного подкласса Tautology, как показано выше.


0

Вы можете просмотреть примеры java doc или пример использования Predicate здесь

В основном он используется для фильтрации строк в наборе результатов на основе любых конкретных критериев, которые могут у вас быть, и возврата true для тех строк, которые соответствуют вашим критериям:

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

    // set the filter.
    resultset.beforeFirst();
    resultset.setFilter(filter);

Я имел в виду предикат общих ресурсов, а не набор результатов. хотя спасибо
srikanth

0

Добавляя к тому, что сказал Майкл :

Вы можете использовать Predicate для фильтрации коллекций в 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;
}

один из возможных предикатов может быть:

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

Использование:

 final List<DisplayFieldDto> filteredList=
 (List<DisplayFieldDto>)filter(displayFieldsList, filterCriteria);

1
Разве это не поражает цель? Основная причина выбора функционального подхода - НЕ выполнять итерацию вручную и избавляться от for. Уровень абстракции становится выше и мощнее, однако выполнение for вручную приводит к поражению этой цели и возвращается к низкоуровневой абстракции.
Eugen
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.