简体   繁体   English

为什么这个Java 8流示例不能编译?

[英]Why doesn't this Java 8 stream example compile?

I'm trying to figure out why this code does not compile on JDK 1.8.0_45 : 我想弄清楚为什么这段代码不能在JDK 1.8.0_45上编译:

public class Example<E extends Example<E>> {
    public List<? extends Example<?>> toExamples(Collection<String> collection) {
        return collection.stream()
                .map(v -> lookup(v))
                .collect(Collectors.toList());
    }

    public static <E extends Example<E>> E lookup(String value) {
        return null;
    }
}

Adding a seemingly unnecessary cast fixes it: 添加一个看似不必要的演员修复了它:

public class Example<E extends Example<E>> {
    public List<? extends Example<?>> toExamples(Collection<String> collection) {
        return collection.stream()
                .map(v -> (Example<?>) lookup(v))
                .collect(Collectors.toList());
    }

    public static <E extends Example<E>> E lookup(String value) {
        return null;
    }
}

Here's the error from the compiler: 这是编译器的错误:

Example.java:9: error: incompatible types: inference variable R has incompatible bounds
              .collect(Collectors.toList());
                      ^
  equality constraints: List<Object>
  upper bounds: List<? extends Example<?>>,Object
where R,A,T are type-variables:
  R extends Object declared in method <R,A>collect(Collector<? super T,A,R>)
  A extends Object declared in method <R,A>collect(Collector<? super T,A,R>)
  T extends Object declared in interface Stream

For some reason, the return type of lookup() isn't correctly inferred to something extending Example . 由于某种原因, lookup()的返回类型未正确推断为扩展Example

As Peter Lawrey pointed out , ? extends Example<?> 正如Peter Lawrey指出的那样? extends Example<?> ? extends Example<?> is not compatible with E extends Example<E> . ? extends Example<?>E extends Example<E>不兼容。 Still, even fixing the signature doesn't make type inference work here. 尽管如此,即使修复签名也不会使类型推断工作。

The reason is a known limitation of the type inference as it does not back-propagate through chained method invocations. 原因是类型推断的已知限制,因为它不通过链式方法调用进行反向传播。 In other words, the return type allows to infer the types for the collect(…) invocation but not for the preceding map(…) invocation. 换句话说,返回类型允许推断collect(…)调用的类型,但不能推断前面的map(…)调用。 (see also this answer ) (另见这个答案

But it works for nested method invocations, so the following rewritten method can be compiled: 但它适用于嵌套方法调用,因此可以编译以下重写方法:

public class Example<E extends Example<E>> {
    public <E extends Example<E>> List<E> toExamples(Collection<String> collection) {
        return collection.stream()
            .collect(Collectors.mapping(v -> lookup(v), Collectors.toList()));
    }

    public static <E extends Example<E>> E lookup(String value) {
        return null;
    }
}

Still, you have to rethink the semantics of your code. 但是,您必须重新考虑代码的语义。 A method's type parameter which appears only at the return type can't be correct as it implies that “ whatever the caller substitutes for this type parameter, the method will return the right thing ”. 仅在返回类型中出现的方法的类型参数不能正确,因为它暗示“ 无论调用者如何替换此类型参数,该方法都将返回正确的内容 ”。 Since the method implementation doesn't know what the caller assumes, this is impossible. 由于方法实现不知道调用者假设什么,这是不可能的。 Only returning null or an empty list will work correctly, which is of little use. 只返回null或空列表才能正常工作,这几乎没用。

When you have a ? 当你有? it doesn't equal another ? 它不等于另一个? ie the compiler doesn't see 即编译器没有看到

? extends Example<?>

as a match for 作为匹配

E extends Example<E>

as it cannot assume the two ? 因为它不能假设这两个? are the same. 是相同的。 It could be 它可能是

A extends Example<B>

When you perform the cast, you obscure the constraint so it can match. 执行强制转换时,会隐藏约束以使其匹配。

My guess is that the generic type defined in the static method is not the same as the generic type defined in the class. 我的猜测是静态方法中定义的泛型类型与类中定义的泛型类型不同。 You should be able to make the lookup method non-static so it matches the same type defined in the class level generic declaration: 您应该能够使lookup方法非静态,因此它匹配类级别泛型声明中定义的相同类型:

    public E lookup(String value) {
        return null;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM