我想根据Person类中的一些属性过滤掉重复项。我有一个方法定义如下:
private static <T> Predicate<T> distinctByKeys(final Function<? super T, ?>... keyExtractors)
{
final Map<List<?>, Boolean> seen = new ConcurrentHashMap<>();
return t ->
{
final List<?> keys = Arrays.stream(keyExtractors)
.map(ke -> ke.apply(t))
.collect(Collectors.toList());
return seen.putIfAbsent(keys, Boolean.TRUE) == null;
};
}
对上面方法的调用是这样的:
List<Person> distinctPersons = list.stream()
.filter(distinctByKeys(Person::getFirstName, Person::getLastName))
.collect(Collectors.toList());
在方法定义中,我可以看到参数可以是函数实现,但在上述代码中传递的参数是供应商类型(因为它们返回结果而不接受任何参数)。但这很好。有谁能解释它是如何工作的吗?
如果您使用使用Type::method
的方法引用,其中method
是非静态的,则有一个显式参数用于调用该方法的对象。在您的示例中,Person::getFirstName
与(Person p) -> p.getFirstName()
类似。
上述代码中传递的参数为
Supplier
类型(就像它们一样)返回结果并且不接受任何参数。但这很好。是如何
在以下代码中:
.filter(distinctByKeys(Person::getFirstName, Person::getLastName))
方法引用Person::getFirstName
和Person::getLastName
不是Supplier
类型,它们是Funtion
类型,因为它们做需要Person
类型的参数,以便返回一个人的名或姓。
在第一个示例中,我简单地将distinctByKeys和forSupplier方法分配给Function接口。然后我只需要apply(execute) method和apply method by given parameters。
从第二个示例中可以看到,也可以使用provider。最后一个例子是你的。但是我有一个问题。
在distinctByKeys方法中的Map实例化有点可疑。我可以想象map是在每个人被filter方法调用时被实例化的,所以这意味着它每次都会返回true,因为map是空的,并且map中没有键,这是由seen查询的。putIfAbsent(keys, Boolean.TRUE)方法调用。
private static Predicate functionExample() {
Function<Function[], Predicate> f = Scratch::distinctByKeys;
Function<Supplier[], Predicate> f2 = Scratch::forSupplier;
f2.apply(new Supplier[0]);
return f.apply(new Function[0]);
}
private static <T> Predicate<T> forSupplier(final Supplier<? super T>... suppliers) {
final Map<List<?>, Boolean> seen = new ConcurrentHashMap<>();
return t ->
{
final List<?> keys = Arrays.stream(suppliers)
.map(Supplier::get)
.collect(Collectors.toList());
return seen.putIfAbsent(keys, Boolean.TRUE) == null;
};
}
private static <T> Predicate<T> distinctByKeys(final Function<? super T, ?>... keyFields)
{
final Map<List<?>, Boolean> seen = new ConcurrentHashMap<>();
return t ->
{
final List<?> keys = Arrays.stream(keyFields)
.map(ke -> ke.apply(t))
.collect(Collectors.toList());
return seen.putIfAbsent(keys, Boolean.TRUE) == null;
};
}