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

时间:2018-02-18 15:10:28

标签: java generics reflection java-8 predicate

例如,我有课

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)行为吗?

我想像这样返回Predicate

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

同样适用于其他类:

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

1 个答案:

答案 0 :(得分:5)

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

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是什么以及为什么需要创建实用程序类的实例。
  • 我直接从字段中获取值而不使用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