コードはjavacのEclipseでコンパイルしなく:機能的なサブインターフェイスを持つカリーラムダを。どちらが正しい?

アーロンRotenbergの:

私は、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()からMyFunctionFunction、またはワイルドカードを除去する? 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のバージョンはテスト:

howlger:

あなたがに実行するように見えますJDKのバグJDK-8156954のJava 9ではなく、Javaの8に固定されています。

これは、Java 8のバグであるjavacため、すべての例では、変数の型transform方法を推測することができ、次のようにJava言語仕様に違反することなく:

  • FString(最初のパラメータを介してoriginalList型のList<String>
  • TIntToByteFunction(戻り値の型を経由して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のジェネリックとの組み合わせでラムダ関数でのみ発生します。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=167384&siteId=1