Java谓词


100

我正在研究Predicate在Java 中使用的代码。我没用过Predicate。有人可以指导我学习任何有关PredicateJava的教程或概念性解释及其实现吗?


4
您是在谈论番石榴Predicate吗?相似的东西?还有其他东西吗?
polygenelubricants 2010年

2
还有Apache CommonsPredicate
Dan Gravell,2010年

Answers:


203

我假设您是在谈论com.google.common.base.Predicate<T>番石榴。

从API:

确定给定输入的truefalse值。例如,一个RegexPredicatemay可能实现Predicate<String>,并且对与其给定正则表达式匹配的任何字符串返回true。

这本质上是boolean测试的OOP抽象。

例如,您可能有这样的帮助方法:

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

现在,给定一个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的其余部分进行互操作,例如,该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);
    }

请注意,现在不进行if测试,for-each循环要简单得多。Iterable<Integer> evenNumbers通过filter使用定义,我们已经达到了更高的抽象层次Predicate

API链接


关于高阶函数

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.filterIterables.all。当然,您可以在Java中传递对象。因此,Predicate定义了类型,然后传递对象实现此接口的。

也可以看看


4
我指的不是Guava的谓词,我应该在问题中明确指出。感谢您的详尽解释
srikanth 2010年

@polygenelubricants,为什么要发明Predicate<Integer>已经存在的F<Integer, Boolean>东西呢?
Pacerier 2014年

您也可以按照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;
     }
}

为了获得更好的概念性理解,您可能需要阅读一阶逻辑。

编辑 Java自Java 8起,在Java API 定义了
一个标准的Predicate接口(java.util.function.Predicate),在Java 8之前,您可能会发现从以下位置重用com.google.common.base.Predicate接口很方便。番石榴

另外,请注意,从Java 8开始,使用lambda编写谓词要简单得多。例如,在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);

我指的是公共谓词,而不是与Resultset有关的谓词。不过谢谢
srikanth 2010年

0

加起来米歇尔说:

您可以在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
那基本上不是打败目的吗?选择功能性方法的主要原因是不要手动进行迭代并摆脱它。抽象级别变得越来越高,功能也越来越强大-但是手动执行该操作会破坏该目的,并返回到低级别抽象。
尤金(Eugen)2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.