有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java 8可选版本中flatMap的签名

oracle docs中,它似乎是

<U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper)

对于mapper作为Function,它使参数反变,但不使返回类型协变。我想知道mapper是否可以(应该)被删除

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

或者

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

?


共 (2) 个答案

  1. # 1 楼答案

    首先,在我看来,由于U绑定到方法本身,而不是类Optional,而且Optionalfinal,所以当前签名应该可以正常工作

    如果上述两个条件中的任何一个不成立,则可以应用更改。感谢@MalteHartwig提供的link。让我总结一下这个问题的答案。很明显,如果返回类型需要是协变的,Java 8中就需要后一个签名(较长的)。这不仅仅是关于继承^在Optional<? extends U>前面需要{}来声明Function的用户站点方差,即使Optionalfinal。我制作了一段代码片段来演示:

    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将该声明从要声明差异的类型变量一直传播到(第二)最外层

  2. # 2 楼答案

    假设你有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>());
    

    正如所料,一切都很好