为 Supplier<? 使用 lambda 时编译失败扩展类型>

Compilation fails when using a lambda for Supplier<? extends Type>

为什么不能编译? :

import java.util.Optional;

public class Demo {

    Optional<? extends SomeValue> getOption() {
        return Optional.empty();
    }

    void exposure() {
        SomeValue someValue = getOption().orElseGet(() -> new SomeValue());
    }
}

class SomeValue {}

getOption() 将 return a Optional<SomeValue>.

时,它可以正常工作

Optional<T>.orElseGet 被指定为接受一个 Supplier<? extends T>。但是 Optional<? extends SomeValue> 的意思是它可能是一个 Optional<MySubClassOfSomeValue>,在这种情况下 Supplier<SomeValue> 就不会是 Supplier<? extends MySubClassOfSomeValue>.

orElseGet 必须 return 是 Optional 元素类型的子类型,并且 ? extends SomeValue 可以是 SomeValue.[=20 以外的其他类型=]

这是相当受限的方法签名的结果:

public T orElseGet(Supplier<? extends T> other) {

在您的例子中,T? extends SomeValue,这是一个未知类型,可分配给 SomeValue(但可能是它的子类)。 orElseGet 的签名意味着允许您的供应商 return T 的子类型,具有 T 的总体结果类型,但不允许扩大到T 的通用基本类型和您的供应商类型 returns(如果您的供应商 returns SomeValueT? extends SomeValue,则常见的基本类型是 SomeValue).

您可以通过插入允许扩大类型的操作来解决此问题:

SomeValue someValue = getOption()
  .map(Function.<SomeValue>identity()).orElseGet(() -> new SomeValue());

identity函数不改变值,但是映射操作允许传入一个消耗更广泛类型的函数,即映射函数可以在实际输入时声明消耗SomeValue类型是 ? extends SomeValue 并且 return 类型是 SomeValue.


但一般来说,为了避免此类问题,方法的 return 类型中不应包含通配符,因此请更改

Optional<? extends SomeValue> getOption()

Optional<SomeValue> getOption()

http://docs.oracle.com/javase/tutorial/java/generics/wildcardGuidelines.html

Using a wildcard as a return type should be avoided because it forces programmers using the code to deal with wildcards.