为什么类型推断在这里失败?

时间:2018-01-30 00:35:38

标签: java generics intellij-idea java-8

所以,我制作了这个相对的简单代码,我和IntelliJ IDEA都没有看到它有什么问题,但是javac在标记的行上徘徊,抱怨它无法推断出类型:< / p>

import java.util.List;
import java.util.stream.Collectors;

public class GenericsBreakJavac8 {

    public interface Edge<N> {
        N getNode();
    }

    @FunctionalInterface
    public interface EdgeCreator<N, E extends Edge<N>> {
        E createEdge(N node);
    }

    public static <N> List<Edge<N>> createEdges(List<N> nodes) {
        return createEdges(nodes, DefaultEdge::new); //the deadly line
    }

    //THE NEWLY ADDED LINE (see the edit note)
    public static <N> List<Edge<N>> createEdges2(List<N> nodes) {
        return createEdges(nodes, n -> new DefaultEdge<N>(n));
    }

    public static <N, E extends Edge<N>> List<E> createEdges(List<N> nodes, EdgeCreator<N, E> edgeCreator) {
        return nodes.stream().map(edgeCreator::createEdge).collect(Collectors.toList());
    }

    public static class DefaultEdge<N> implements Edge<N> {
        private final N node;

        public DefaultEdge(N node) {
            this.node = node;
        }

        @Override
        public N getNode() {
            return node;
        }
    }
}

使用显式类型将有问题的行拆分为2会有所帮助,但类型签名比lambda长,完全违背了编写lambda的目的......

修改 如果我使用实际的lambda而不是方法引用,我会再次遇到问题。请参阅上面新添加的方法。

2 个答案:

答案 0 :(得分:8)

javac并不认为DefaultEdge是原始类型。

    return createEdges(nodes, DefaultEdge<N>::new);

将按预期工作。

答案 1 :(得分:4)

除了Jeffrey’s answer之外,请注意您的EdgeCreator界面在功能上与Function没有区别,createEdges实际上并不需要有问题的类型约束。因此,一个解决方案是让EdgeCreator扩展Function以简化createEdges

import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

public class GenericsBreakJavac8 {

    public interface Edge<N> {
        N getNode();
    }

    @FunctionalInterface
    public interface EdgeCreator<N, E extends Edge<N>> extends Function<N,E> {
        E createEdge(N node);
        @Override public default E apply(N t) { return createEdge(t); }
    }

    public static <N> List<Edge<N>> createEdges(List<N> nodes) {
        return createEdges(nodes, DefaultEdge::new);
    }

    public static <N> List<Edge<N>> createEdges2(List<N> nodes) {
        return createEdges(nodes, n -> new DefaultEdge<>(n));
    }

    public static <T,R> List<R> createEdges(List<T> nodes, Function<T,R> edgeCreator) {
        return nodes.stream().map(edgeCreator).collect(Collectors.toList());
    }

    public static class DefaultEdge<N> implements Edge<N> {
        private final N node;

        public DefaultEdge(N node) {
            this.node = node;
        }

        @Override
        public N getNode() {
            return node;
        }
    }
}

您也可以删除EdgeCreator接口,并在需要强制执行约束的地方使用Function<N, E extends Edge<N>>,但在此代码中,没有这样的地方。当有人试图使用createEdges(List,Function)时,约束仍然会被强制执行。其结果,在上下文中,需要List<Edge<SpecificNodeType>>

对太多代码位置进行类型约束只会让您的源代码膨胀而无益。

顺便说一下,在你当前的代码中,你甚至不需要DefaultEdge类;你可以将整个代码简化为

import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

public class GenericsBreakJavac8 {

    public interface Edge<N> {
        N getNode();
    }

    public static <N> List<Edge<N>> createEdges(List<N> nodes) {
        return createEdges(nodes, n -> () -> n);
    }

    public static <T,R> List<R> createEdges(List<T> nodes, Function<T,R> edgeCreator) {
        return nodes.stream().map(edgeCreator).collect(Collectors.toList());
    }
}