私は、Eclipseでいくつかのコードを開発に成功し、それをテストし、私たちのジェンキンスCIサーバにそれをプッシュし、Mavenのは、Javaのコンパイルエラーで窒息されたことを電子メールを得ました。私はその後、問題を分離し、問題を示す、次の最小限の例を作成しました:
import java.util.List;
import java.util.function.Function;
class MinimalTypeFailureExample {
public static void main(String[] args) {
List<String> originalList = null; // irrelevant
List<IntToByteFunction> resultList = transform(originalList,
outer -> inner -> doStuff(inner, outer));
System.out.println(resultList);
}
static <F, T> List<T> transform(List<F> originalList,
MyFunction<? super F, ? extends T> function) {
return null; // irrelevant
}
static Byte doStuff(Integer inner, String outer) {
return null; // irrelevant
}
}
@FunctionalInterface
interface MyFunction<F, T> extends Function<F, T> {
@Override
T apply(F input);
}
@FunctionalInterface
interface IntToByteFunction {
Byte applyIntToByte(Integer inner);
}
Eclipseで、このコードのエラーなしでコンパイルし、意図したとおりに実行するように見えます。しかし、javacのでコンパイルすると、次のエラーを与えます:
MinimalTypeFailureExample.java:7: error: incompatible types: cannot infer type-variable(s) F,T
List<IntToByteFunction> resultList = transform(originalList, outer -> inner -> doStuff(inner, outer));
^
(argument mismatch; bad return type in lambda expression
T is not a functional interface)
where F,T are type-variables:
F extends Object declared in method <F,T>transform(List<F>,MyFunction<F,? extends T>)
T extends Object declared in method <F,T>transform(List<F>,MyFunction<F,? extends T>)
1 error
引数の型を変更することtransform()
からMyFunction
のFunction
、またはワイルドカードを除去する? extends
引数の型に、javacの例コードのコンパイルを行います。
明らかに、Eclipseやjavacのどちらかは、Java言語仕様に違反しています。質問は、私はEclipseやjavacの上のバグレポートを提出しますか?ジェネリックラムダのための型推論ルールは、私はこのプログラムはJLSによる正当なJavaであるかどうか分からないほど複雑です。
モチベーションノート
元のコードでは、
transform()
グアバのでしたcom.google.common.collect.Lists.transform()
。MyFunction
インタフェースは、グアバのあっcom.google.common.base.Function
延びインターフェース、java.util.function.Function
歴史的な理由。このコードの目的は、第二のタイプのリストである第1の種類のリストのビューを作成することでした。第二のタイプは、機能的なインターフェイスタイプであり、私は、この種の機能は、入力リスト従ってカリーラムダ式の値に基づいて構築して出力リストに移入したかったです。
再現のためのバージョン情報
Eclipseのバージョンはテストしました:
- 2018から09(4.9.0)ビルドID:20180917から1800
- 2019から03 RC1(4.11 RC1)ビルドID:20190307から2044
javacのバージョンはテスト:
- 1.8.0_121
- 経由JDK 10.0.1 JDoodleオンラインJavaコンパイラ
あなたがに実行するように見えますJDKのバグJDK-8156954のJava 9ではなく、Javaの8に固定されています。
これは、Java 8のバグであるjavac
ため、すべての例では、変数の型のtransform
方法を推測することができ、次のようにJava言語仕様に違反することなく:
F
:String
(最初のパラメータを介してoriginalList
型のList<String>
)T
:IntToByteFunction
(戻り値の型を経由してList<IntToByteFunction>
)
これらの推論変数タイプがあると互換性のある第二のパラメータのタイプ連鎖ラムダ式:
outer -> inner -> doStuff(inner, outer)
解決さ(とdoStuff(Integer, String)
へString -> Integer -> doStuff(Integer, String)
解決さへString -> Integer -> Byte
と互換性がありますString -> IntToByteFunction
と互換性がありますMyFunction<? super String, ? extends IntToByteFunction>
あなたの例では、さらに最小化することができます。
import java.util.function.Function;
class MinimalTypeFailureExample {
void foo() {
transform((Function<Integer, String>)null, o -> i -> {return "";});
}
<T, F> void transform(F f, MyFunction<T, ? extends F> m) {}
}
@FunctionalInterface
interface MyFunction<T, R> extends Function<T, R> {
@Override
R apply(T t);
}
MyFunction
(同じで同じことを優先しますR apply(T t);
)。もしFunction
代わりにMyFunction
使用されている場合、またはMyFunction
拡張Function
が、なしの@Override R apply(T t);
エラーが消えた後。また、とのF
代わりに? extends F
エラーが表示されなくなります。
でも、上記のバグの例からあなたの例が異なる場合は、唯一であるので、それは同じバグであると仮定することができる「引数の不一致、ラムダ式の中に不正な戻り値の型のJava 9ではなく、Javaで固定されているバグ8とそのJavaのジェネリックとの組み合わせでラムダ関数でのみ発生します。