【问题标题】:Java functional generics [duplicate]Java函数泛型[重复]
【发布时间】:2018-04-27 04:57:21
【问题描述】:

Map 的ComputeIfAbsent 方法有如下声明:

computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction).

当 K 和 V 类型不在其他任何地方使用时,为什么不将参数声明为 Function<K,V>?

现在我明白了 K 和 V 非常重要,它们是 Map 类声明的一部分。

【问题讨论】:

  • 一般要明确什么是可以接受的。例如,只要超类是 K,第二个参数只要扩展 V,就可以将任何内容传递给函数。否则可能会导致误解。
  • K 和V 是Map 的参数为什么你认为它们没有被使用?
  • 值得一看here。我什至可能会说这个问题是重复的。

标签: java generics functional-programming


【解决方案1】:

K 和V 是映射函数类型的一部分。所以它们实际上是被使用的。具体来说,它们确定参数类型和映射函数的返回类型的可接受和最一般的界限。

对于

Function<? super K,? extends V> mappingFunction

这意味着您可以传递任何函数,该函数至少能够映射所有可以作为映射中键的所有内容(因此 ? super K)并将这些键映射到可以放入映射中的值(因此 @ 987654325@)。实际上,这使您在选择映射函数时更加灵活。

在更理论的术语中:子类型函数在其参数类型上是逆变的,在其返回类型上是协变的。当将Map&lt;K, V&gt; 视为从K 到V 的函数时,这将确定mappingFunction 到Function&lt;? super K,? extends V&gt; 的类型。

【讨论】:

    【解决方案2】:

    简单示例:

    Map<String,Object> myMap = ...
    Function<Object,String> myFunc = Object::toString;
    myMap.computeIfAbsent("42", myFunc);
    

    这可以接受吗?

    好吧,假设 myFunc 的类型是 Function&lt;Object,String&gt;,而我们有一个 Map&lt;String,Object&gt;,听起来好像有问题。如果你只接受Function&lt;K,V&gt;,它肯定不会编译。

    但是当你仔细观察它时,并没有什么问题。代码不仅可以证明有效,而且很容易看出它为什么有效:"42" 是String 的一个实例,它有一个toString() 方法。该方法返回一个String,当然是Object。所以当然没问题。

    而这种“精细”就是Function&lt;? super K, ? extends V&gt;所表达的。

    【讨论】:

    • 实际上,myMap.computeIfAbsent("42", Object::toString) 仍然编译,如果方法的参数声明为Function&lt;K,V&gt;,因为编译器足够聪明,可以将Object::toString 绑定为Function&lt;String,Object&gt;,例如你也可以写Function&lt;String,Object&gt; f = Object::toString; 而不会出错。这就是为什么 lambda 表达式和方法引用会成为不好的例子。尝试现有功能,例如computeIfAbsent(myMap, "42", Function.identity()) 将不再编译。但是,这些问题只是“什么是 PECS”的重复......
    • @Holger 你当然是对的。我会修正这个例子。
    猜你喜欢
    • 1970-01-01
    • 2011-12-24
    • 1970-01-01
    • 1970-01-01
    • 2013-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-26
    相关资源
    最近更新 更多