Java函数式泛型

12 浏览
0 Comments

Java函数式泛型

Map的computeIfAbsent方法具有以下声明:

computeIfAbsent(K key, Function mappingFunction)

为什么参数没有声明为Function,当K和V类型在其他地方都没有使用?

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

0
0 Comments

Java的泛型机制中出现了一个问题,即Java函数式泛型。这个问题的出现原因是因为K和V是映射函数类型的一部分,所以它们实际上是被使用的。具体来说,它们确定了映射函数的参数类型和返回类型的可接受和最一般的边界。

对于Function mappingFunction来说,这意味着您可以传递任何能够将作为映射函数中的键的任何东西进行映射的函数(因此? super K),并将这些键映射到可以放入映射中的值(因此extends V)。实际上,这使您在选择映射函数时更加灵活。

更具有理论意义的是:在子类型化函数中,参数类型是逆变的,返回类型是协变的。当将Map视为从K到V的函数时,这决定了mappingFunction的类型为Function

解决这个问题的方法是使用通配符来限定参数类型和返回类型的范围。通过使用通配符,我们可以在传递映射函数时获得更大的灵活性。

0
0 Comments

Java 泛型中的问题和解决方法

在上述代码中,我们定义了一个泛型的 Map 对象 myMap,其键的类型是 String,值的类型是 Object。然后我们定义了一个 Function 对象 myFunc,它将 Object 类型转换为 String 类型。接着我们调用了 myMap 的 computeIfAbsent 方法,传入了键值 "42" 和 myFunc。

这段代码的问题在于,myFunc 的类型是 Function,而我们的 myMap 的值类型是 Object。按照类型推断的规则,在这种情况下是无法通过编译的。但是当我们仔细观察代码时,我们会发现这段代码实际上是没有问题的。不仅代码可以正常工作,而且我们也很容易看出为什么它可以工作:字符串 "42" 是 String 类型的实例,而 String 类型有一个 toString() 方法,该方法返回一个 String 对象,而 String 对象又是 Object 类型的子类,所以当然没有问题。

这种“没有问题”的情况正是由 Function 表达的。实际上,即使我们将方法的参数声明为 Function,代码 myMap.computeIfAbsent("42", Object::toString) 仍然可以编译通过,因为编译器足够智能,可以将 Object::toString 绑定为 Function。例如,我们也可以写成 Function f = Object::toString; 而不会出错。这就是为什么 lambda 表达式和方法引用不是很好的示例。如果我们使用已有的函数,比如 computeIfAbsent(myMap, "42", Function.identity()),那么代码将无法编译通过。但这个问题其实只是“什么是 PECS”的一个重复问题...

你说得对,我会修复这个示例。

0