在java 8中传递Supplier而不是Function作为参数



我想根据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::getFirstNamePerson::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;
};
}

最新更新