2017-02-27 37 views
4

我使用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()); 

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

+0

因为编译器就会犯糊涂?您应该在左侧和右侧发布代码 – 2017-02-27 11:52:18

+0

@RC。我添加了'left()'和'right()'的签名 – slim

+0

无法重现。在'javac'和eclipse中这对我来说都很好。 –

回答

2

此代码应工作。

它编译最新的JDK,1.8.0_121。

它无法编译在JDK 1.8.0-51。

这意味着它是最有可能在这个版本的JDK中的错误,因为以后的版本不应更改编译器的行为,除非修正错误。这可能是bug JDK-8055963

因此,解决方案是:

  1. 升级你的编译器
  2. 如果您不能升级编译器(例如其他人,固执,拥有构建系统),坚持使用现有的制作解决方法类型明确。
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()); 
     }); 
    } 
} 
+0

我复制/粘贴到这个'test.java',接着说:进口java.util.function.Function'到您的版本,跑'javac的test.java'并得到“推断的类型不符合上限(s)'。 Javac版本'javac 1.8.0_51'。 – slim

+0

哈!在JDK 1.8.0_121中进行编译,但不在JDK 1.8.0_51中进行编译 - 不知道哪个bug修复程序负责。 – slim

+0

我正在考虑Java版本(7对8)之间的差异,但它已在Java 8版本中修复。有趣。 –

相关问题