如何按类型动态创建通用的 lambda 实现?

How to dynamically create a generic lambda implementation by type?

例如,我有 class

public class Human {

  private String name;

  ...
}

我想实现这样的东西:

(1)

List<Human> humans =  initHumans();
Equals<Human> humanEquals = new Equals<>();
Predicate<Human> filter = humanEquals.filter("name", "John");
List<Human> filteredHumans = humans
    .stream()
    .filter(filter)
    .collect(Collectors.toList());

等于:

public class Equals<T> extends AbstractPredicate<T> {

  public java.util.function.Predicate<T> filter(String fieldName, String fieldValue) {
    ....
  }  
}

是否可以实现过滤器方法来提供 (1) 行为?

我想 return 一个 Predicate 这样的:

Predicate<Human> predicate = human -> human.getName().equals("John");

同样适用于其他 classes:

Predicate<Car> filter = humanEquals.filter("color", "red");
//like this:
Predicate<Car> predicate= human -> human.getColor().equals("red");

是的,这可以通过反射来实现:

public static <T> Predicate<T> filter(Class<T> clazz, String fieldName, Object fieldValue) {
    // 1
    return (T instance) -> {
        try {
            final Field field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);

            return fieldValue.equals(field.get(instance));
        } catch (NoSuchFieldException | IllegalAccessException e) {
            // 2
        }
        return false;
    };
}
  • 我创建了一个方法 static 因为我不知道 AbstractPredicate 是什么以及为什么需要创建实用程序的实例 class.
  • 我在不使用 getter 的情况下直接从字段中获取值 - 我们应该遵守什么命名约定? (可能会有所改进)

用途是:

final Predicate<Human> filter = Equals.filter(Human.class, "name", "John");

System.out.println(filter.test(new Human("John")));     // true
System.out.println(filter.test(new Human("Andrew")));   // false

还有几个问题需要我们思考——验证参数(1),处理异常(2)。


另一个选项可以使用 Function<T, E> 来提供对 getter 的引用:

public static <T, E> Predicate<T> filter(Function<T, E> supplier, E value) {
    return (T instance) -> supplier.apply(instance).equals(value);
}

使用示例:

final Predicate<Human> predicate = Equals.filter(Human::getName, "John");

System.out.println(predicate.test(new Human("John")));    // true
System.out.println(predicate.test(new Human("Andrew")));  // false