为什么这个分支打破类型推断?

时间:2017-02-27 11:48:40

标签: java type-inference

我在Java中使用了Either的本地实现,它有这样的方法:

public static <L, R> Either<L, R> left(final L value);

public static <L, R> Either<L, R> right(final R value);

public <T> T fold(
        final Function<? super L, ? extends T> leftFunction,
        final Function<? super R, ? extends T> rightFunction); 

这两种方法编译并正常工作:

Either<Foo, Bar> rightToLeft() {
    Either<Foo, Bar> input = Either.right(new Bar());
    return input.fold(
        l -> null, 
        r -> Either.left(new Foo())
    );
}

Either<Foo, Bar> rightToRight() {
    Either<Foo, Bar> input = Either.right(new Bar());
    return input.fold(
        l -> null,
        r -> Either.right(new Bar())
    );
}

此方法无法编译:

Either<Foo, Bar> rightToLeftOrRightConditionally() {
    Either<Foo, Bar> input = Either.right(new Bar());
    return input.fold(
        l -> null, 
        r -> {
            if (r.equals("x")) {
               return Either.left(new Foo());
            }
            return Either.right(new Bar());
        });
}

错误:

incompatible types: inferred type does not conform to upper bound(s)
    inferred: Either<? extends Object,? extends Object>
    upper bound(s): Either<Foo,Bar>,java.lang.Object

(我已经删除了包限定符以使错误更具可读性)

我可以通过指定类型进行编译:

if (r.equals("x")) {
    return Either.<Foo, Bar> left(new Foo());
}
return Either.<Foo, Bar> right(new Bar());

但为什么我需要?我怎样才能避免这种代码混乱?

2 个答案:

答案 0 :(得分:2)

此代码应该有效。

它汇编了最新的JDK,1.8.0_121。

无法在JDK 1.8.0-51上编译。

这意味着它很可能是此版本JDK中的错误,因为除非修复错误,否则更高版本不应更改编译器的行为。它可能是错误JDK-8055963

所以,解决方案是:

  1. 升级您的编译器
  2. 如果您无法升级编译器(例如,其他人,顽固的,拥有构建系统),请坚持使用现有的解决方法,使类型明确。

答案 1 :(得分:1)

我没有看到你的全班,但这段代码为我编译:

class Foo{}
class Bar{}

class Either<L,R> {

    private L left;
    private R right;

    public Either(L left, R right) {
        this.left = left;
        this.right = right;
    }

    public static <L, R> Either<L,R> left(L l) {
        return new Either<>(l, null);
    }

    public static <L, R> Either<L,R> right(R r) {
        return new Either<>(null, r);
    }


    public <T> T fold(
            final Function<? super L, ? extends T> leftFunction,
            final Function<? super R, ? extends T> rightFunction) {
        return null;
    }

    Either<Foo, Bar> rightToLeft() {
        Either<Foo, Bar> input = Either.right(new Bar());
        return input.fold(
                l -> null,
                r -> Either.left(new Foo())
        );
    }

    Either<Foo, Bar> rightToRight() {
        Either<Foo, Bar> input = Either.right(new Bar());
        return input.fold(
                l -> null,
                r -> Either.right(new Bar())
        );
    }

    Either<Foo, Bar> rightToLeftOrRightConditionally() {
        Either<Foo, Bar> input = Either.right(new Bar());
        return input.fold(l -> null, r -> {
            if (r.equals("x")) {
                return Either.left(new Foo());
            }
            return Either.right(new Bar());
        });
    }
}