Java 8中Optional的flatMap方法签名解析

13
Oracle文档中,它似乎是关于IT技术方面的内容。
<U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper)

作为一个`Function`,`mapper`会使得参数的协变性变弱,但并不会使得返回类型的逆变性变强。我想知道是否应该让`mapper`可以(或应该)这样做。
Function<? super T,Optional<? extends U>>

或者
Function<? super T, ? extends Optional<? extends U>>

?


5
好问题,似乎在Java 9中已经有所改变。Optional是一个final类,因此没有任何东西可以继承它,但U可以是任何类型。 - Bubletan
8
是的,该函数的返回类型原本应该是协变的。这在Java 9中得到了修复。请参阅 JDK-8152617。请注意,即使 Optional 是 final,嵌套通配符也是必需的。有关详细信息,请参见审核线程(从错误报告链接中链接)。 - Stuart Marks
1
为了未来的读者,这是一个快捷方式,可以让您直接跳转到评论线程中的一篇文章,Stuart Marks在其中解释了这个更改的必要性:http://mail.openjdk.java.net/pipermail/core-libs-dev/2016-October/044026.html - Malte Hartwig
2个回答

1
首先,我认为由于U绑定到方法本身而不是类Optional,并且Optionalfinal,所以当前的签名应该可以正常工作。
如果以上两个条件中的任何一个不成立,则可以应用更改。感谢@MalteHartwig提供的链接。让我总结一下对这个特定问题的答案。很明显,如果返回类型需要协变,Java 8中必须使用后面的签名(较长的那个)。这不仅涉及继承。即使Optionalfinal,在Function的用户站点方差声明中也需要在Optional<? extends U>前加上? extends。我制作了一个代码片段来演示它:
import java.util.function.Function;

class A {}
class B extends A {}

final public class Option<T> {
  private T value;
  public Option(T v) { value = v; }
  <U> Option<? extends U> flatMap1(Function<? super T, Option<? extends U>> mapper) {
    return mapper.apply(value);
  }

  <U> Option<? extends U> flatMap2(Function<? super T, ? extends Option<? extends U>> mapper) {
    return mapper.apply(value);
  }

  void test() {
    Option<A> oa = new Option<>(new A());
    Function<A,Option<A>> faa = (A a) -> new Option<>(new A());
    Function<A,Option<B>> fab = (A a) -> new Option<>(new B());
    //oa.flatMap1(faa);   DOES NOT COMPILE
    oa.flatMap2(fab);
  }
}

看起来由于Java只有用户站点的差异声明,您可能需要一系列? extends将该声明传播到要声明差异的类型变量的(第二个)最外层级别。


0

假设你有一个class Aclass B extends A,你需要记住一个对象B是一个A对象;你从它那里继承。

为了使一个对象满足Optional<? extends U>的约束条件,它必须满足Optional<U>的约束条件。同样地,为了使一个对象满足Optional<U>的约束条件,它必须满足Optional<? extends U>

在这种情况下,它们是同义词。

虽然问题特定于某个方法,但你可以很容易地测试答案。通过编写类似的函数,你可以测试编译器是否允许你想要的,并且它是否按预期运行。

public static <U> void List(List<U> A, List<? extends U> B) {
    ...
}
...
MakeList(new ArrayList<Number>(), new ArrayList<Integer>());

正如预期的那样,一切都很好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接