当前位置: 首页 > 知识库问答 >
问题:

在java 8中传递供应商而不是函数作为参数

焦苏燕
2023-03-14

我想根据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());

在方法定义中,我可以看到参数可以是函数实现,但上面代码中传递的参数是供应商类型(因为它们返回的是结果,不接受任何参数。但这很好。它是如何工作的?有人能解释吗。

共有3个答案

班承恩
2023-03-14

在第一个示例中,我只是将distinctByKeys和forSupplier方法分配给函数接口。然后我只应用(执行)方法,通过给定的参数应用方法。

也可以使用供应商,正如您从第二个示例中看到的那样。最后一个例子是你的。但我有一个问题。

distinctByKeys方法中的映射实例化有点可疑。我可以想象,当每个人都被filter方法调用时,map被实例化,这意味着每次它都会返回true,因为map是空的,并且seen查询的map中没有键。putIfAbsent(键,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;
    };
}
刘选
2023-03-14

上述代码中传递的参数是供应商类型(因为它们返回结果,不接受任何参数。但这很好。它是如何工作的?有人能解释吗。

在以下代码中:

.filter(distinctByKeys(Person::getFirstName, Person::getLastName))

方法引用Person::getFirstName和Person::getLastName不是供应商的类型,它们是函数,因为它们需要Person类型的参数才能返回一个人的名字或姓氏。

都昊乾
2023-03-14

如果您使用使用Type::方法的方法引用,其中method是非静态的,则有一个显式参数供对象调用该方法。在您的例子中,Person::getFirstName类似于(Person p)-

 类似资料:
  • 为什么供应商只支持无参数构造函数? 如果默认构造函数存在,我可以这样做: 但如果唯一的构造函数采用字符串,我必须这样做:

  • 问题内容: 我似乎记得在PHP中,有一种方法可以将数组作为函数的参数列表传递,以标准方式取消对数组的引用。但是现在我迷失了如何做。我记得通过引用传递的方式,如何“遍历”传入的参数……但没有如何将数组从列表中除名。 它可能和一样简单,但是我敢肯定不是。但是,可悲的是,到目前为止,php.net手册还没有透露任何内容。并不是说我在过去一年左右的时间里不得不使用此特定功能。 问题答案: call_use

  • 我有一个接口,其参数可以为空。 为了避免空参数和空检查,通常的建议是使用方法重载: 在某些情况下,我不喜欢这种方法,因为它迫使客户做这种工作: 客户端使用更方便: 初看起来,可选选项可以解决这个问题,但是“可选”不应该用于参数https://rules.sonarsource.com/java/RSPEC-3553 所以我的问题是:我可以用供应商来代替吗? 以至 这个想法没有任何警告。 我个人很喜

  • 为什么Java中的方法将作为参数,而不是?这是一个问题,我找到的最好的答案是在这里,说明 这里最重要的概念是,通过提供方法引用(或函数),可以懒惰地初始化它。如果不需要,则不需要创建异常对象。只在你需要的时候创建它。 但我还是不明白。为什么对象创建不能是懒惰的?

  • 问题内容: 我想使用数组作为参数调用一个函数: 有路过的内容的一种更好的方式进入? 问题答案: const args = [‘p0’, ‘p1’, ‘p2’]; call_me.apply(this, args); 请参阅MDN文档。 如果环境支持ECMAScript6,则可以改用传播参数:

  • 问题内容: 如何在不执行“父”函数或不使用函数的情况下将函数作为参数传递?(因为我已经读到它是不安全的。) 我有这个: 它可以工作,但是问题是在调用函数时触发,而不是在函数中使用时触发。 根据我所读的内容,我可以使用来解决它,但这不是最佳实践。如何在JavaScript中将函数作为参数传递? 问题答案: 您只需要删除括号: 然后,这将传递函数而不先执行它。 这是一个例子: