2017-02-27 20 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); 

これらの2つの方法は、コンパイルして正常に動作:

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

コンパイラが混乱するためですか? 'left'と' right'のコードを投稿するべきです –

+0

@RC。私は 'left()'と 'right() 'の署名を追加しました – slim

+0

再現できません。これは 'javac'とeclipseの両方で、うまくコンパイルされます。 –

答えて

2

このコードは動作するはずです。

最新のJDK、1.8.0_121でコンパイルされます。

JDK 1.8.0-51でコンパイルできません。

これは、このバージョンのJDKでバグが発生する可能性が高いことを意味します。これは、バグを修正するまでコンパイラの動作を変更しないでください。バグ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'にコピー&ペーストし、あなたのバージョンに 'import java.util.function.Function'を追加し、' javac test.java'を実行しました。 '推定された型は上限に適合しません'。 Javacバージョン 'javac 1.8.0_51'。 – slim

+0

ハ! JDK 1.8.0_121ではコンパイルされますが、JDK 1.8.0_51ではコンパイルされません。 – slim

+0

私はJavaバージョン(7対8)の違いについて考えていましたが、Java 8リリースで修正されました。面白い。 –

関連する問題