在java 8中获取编译错误“推断类型不符合上限”

时间:2018-02-06 20:34:29

标签: java intellij-idea lambda types functional-programming

我正在开发一个小程序,我正在尝试使用Java 8学习更多功能的编程风格。

这是有问题的代码

private Function<String, IOMessage<List<Polygon>>> parseSuccessfulShapesInput = (input) -> {
    try {
        List<Polygon> shapes =
                Arrays.stream(input.split(";"))
                        .map(shape -> Arrays.stream(shape.split(","))
                                .map(pointString -> Arrays.asList(pointString.trim().split(" ")))
                                .map(coordList -> {
                                    if (coordList.size() != 2) {
                                        throw new RuntimeException("Points given must contain exactly two coordinates");
                                    } else {
                                        return new Point(Double.valueOf(coordList.get(0)), Double.valueOf(coordList.get(1)));
                                    }
                                }).collect(Collectors.toList()))
                        .map(Polygon::new)
                        .collect(Collectors.toList());
        return new IOMessage.Success<>(shapes);

    } catch (Exception e) {
        Exception fail = new Exception("Failed to parse shapes input.", e);
        return new IOMessage.Error<>(fail);
    }
};

private Function<IOMessage<String>, IOMessage<List<Polygon>>> parseShapesInput = (input) -> 
    input.match((IOMessage.Success<String> s) -> parseSuccessfulShapesInput.apply(s.payload),
            (IOMessage.Error e) -> new IOMessage.Error<>(e.t),
            (IOMessage.Quit q) -> new IOMessage.Quit<>()
    );

我的IDE(Intellij)没有显示任何错误,但是当我编译它时,我收到以下错误:

Error:(107, 20) java: incompatible types: bad return type in lambda expression
    inferred type does not conform to upper bound(s)
      inferred: PolyPath.IOMessage<? extends java.lang.Object>
      upper bound(s): PolyPath.IOMessage<java.util.List<PolyPath.Polygon>>,java.lang.Object

如果我尝试将显式类型添加到parseShapesInput,请执行以下操作:

private Function<IOMessage<String>, IOMessage<List<Polygon>>> parseShapesInput = (input) -> {
    return input.match((IOMessage.Success<String> s) -> parseSuccessfulShapesInput.apply(s.payload),
            (IOMessage.Error e) -> new IOMessage.Error<IOMessage<List<Polygon>>>(e.t),
            (IOMessage.Quit q) -> new IOMessage.Quit<IOMessage<List<Polygon>>>()
    );
};

Intellij给了我以下错误:

Incompatible types: IOMessage<capture of ? extends Object> is not convertible to IOMessage<List<Polygon>>

我的IOMessage代码:

public abstract class IOMessage<T> {

    private IOMessage() {
    }

    public abstract <M> M match(Function<Success<T>, M> s,
                                Function<Error, M> e,
                                Function<Quit, M> q);


    public static final class Success<S> extends IOMessage<S> {
        public final S payload;



        public <M> M match(Function<Success<S>, M> s,
                           Function<Error, M> e,
                           Function<Quit, M> q) {
            return s.apply(this);
        }

        public Success(S payload) {
            this.payload = payload;
        }

    }

    public static final class Error<S> extends IOMessage<S> {
        public final Throwable t;

        public <M> M match(Function<Success<S>, M> s,
                           Function<Error, M> e,
                           Function<Quit, M> q) {
            return e.apply(this);
        }

        public Error(Throwable t) {
            this.t = t;
        }
    }

    public static final class Quit<S> extends IOMessage<S> {
        public <M> M match(Function<Success<S>, M> s,
                           Function<Error, M> e,
                           Function<Quit, M> q) {
            return q.apply(this);
        }

        public Quit() {
        }
    }

}

1 个答案:

答案 0 :(得分:1)

我无法解释为什么编译器不喜欢你的代码,但你可以将方法更改为

    private Function<IOMessage<String>, IOMessage<List<Polygon>>> parseShapesInput = (
            input) -> {
        if (input instanceof IOMessage.Success) {
            return parseSuccessfulShapesInput
                    .apply(((IOMessage.Success<String>) input).payload);
        }
        if (input instanceof IOMessage.Error) {
            return new IOMessage.Error<>(((IOMessage.Error<String>) input).t);
        }
        return new IOMessage.Quit<>();
    };

我尝试了不同的东西,如果你删除了ErrorQuit的实例化,并通过parseSuccessfulShapesInput#apply的调用替换它,编译器就会很高兴。我认为最好的解释是编译器有时会混淆(在其他场合也会发生)。

BTW:要摆脱编译器警告(不确定它们是否出现在IntelliJ中,我使用Eclipse),我改变了IOMessage:

import java.util.function.Function;

public abstract class IOMessage<T> {

    private IOMessage() {
    }

    public abstract <M> M match(Function<Success<T>, M> s,
            Function<Error<T>, M> e, Function<Quit<T>, M> q);

    public static final class Success<S> extends IOMessage<S> {
        public final S payload;

        public <M> M match(Function<Success<S>, M> s, Function<Error<S>, M> e,
                Function<Quit<S>, M> q) {
            return s.apply(this);
        }

        public Success(S payload) {
            this.payload = payload;
        }

    }

    public static final class Error<S> extends IOMessage<S> {
        public final Throwable t;

        public <M> M match(Function<Success<S>, M> s, Function<Error<S>, M> e,
                Function<Quit<S>, M> q) {
            return e.apply(this);
        }

        public Error(Throwable t) {
            this.t = t;
        }
    }

    public static final class Quit<S> extends IOMessage<S> {
        public <M> M match(Function<Success<S>, M> s, Function<Error<S>, M> e,
                Function<Quit<S>, M> q) {
            return q.apply(this);
        }

        public Quit() {
        }
    }

}