web-dev-qa-db-ja.com

ラムダ式に置き換えられた匿名クラス

Java 8 new ストリーム機能 (int値の範囲1 .. 20を取得し、最初の9をスキップして、残りの10をそれぞれ取得する)を使用するサンプルコードがあります。 int値:1を減らし、2を掛けます)。

_System.out.println(Arrays.toString(
    IntStream.rangeClosed(1, 20).skip(9).limit(10).map((new IntUnaryOperator() {
        @Override
        public int applyAsInt(int operand) {
            return operand - 1;
        }
    }).andThen(new IntUnaryOperator() {
        @Override
        public int applyAsInt(int operand) {
            return operand * 2;
        }
    })).toArray()));
_

出力は次のとおりです。

_[18, 20, 22, 24, 26, 28, 30, 32, 34, 36]
_

ここで、匿名クラスを ラムダ式 に置き換えたいと思います。次の変換は正常に機能し(2番目の匿名クラスは_i -> i * 2_ラムダ式に置き換えられます)、同じ出力が得られます。

_System.out.println(Arrays.toString(
    IntStream.rangeClosed(1, 20).skip(9).limit(10).map((new IntUnaryOperator() {
        @Override
        public int applyAsInt(int operand) {
            return operand - 1;
        }
    }).andThen(i -> i * 2)).toArray()));
_

ただし、最初の匿名クラスをラムダ式に置き換えると、次のようになります。

_System.out.println(
    Arrays.toString(
        IntStream.rangeClosed(1, 20).skip(9).limit(10)
            .map((v -> v - 1).andThen(i -> i * 2)).toArray()));
_

コードをコンパイルできません。エラーは_Operator '-' cannot be applied to '<lambda parameter>', 'int'_と言います

Compilation error

2つのラムダ式を_IntUnaryOperator.andThen_と組み合わせる方法を知っていますか?

私は....limit(10).map(v -> v - 1).map(i -> i * 2).toArray() ...を使用できることを知っていますが、これは正常に機能しますが、ラムダで_IntUnaryOperator.andThen_を使用する方法を知りたいです(可能な場合)。

21
Tom

最初のラムダ式をIntUnaryOperatorに明示的にキャストする必要があります。次のコードが機能します。

System.out.println(
        Arrays.toString(
                IntStream.rangeClosed(1, 20).skip(9).limit(10)
                        .map(((IntUnaryOperator) v -> v - 1).andThen(i -> i * 2)).toArray()));
15
jpvee

私はコードを次のようにコンパイルすることができました(Eclipseの実験バージョンを使用していますが):

IntUnaryOperator first = v -> v - 1;
IntUnaryOperator second = i -> i * 2;
System.out.println(Arrays.toString(IntStream.rangeClosed(1, 20).skip(9)
                .limit(10).map(first.andThen(second)).toArray()));

firstsecondを宣言せずにコードを記述できることに関心があることを理解しています。ただし、IntUnaryOperatorFunctionalInterfaceであり、Javaコンパイラの動作に基づいて、FunctionalInterfaceができるようにするには「コンテキスト」が必要です。これが、元のコードスニペットJavaコンパイラには、lamda式をIntUnaryOperatorのインスタンスに正確にマップする方法がない理由です。

より長い議論については、このスレッドを見てください: http://mail.openjdk.Java.net/pipermail/jdk8-dev/2013-June/002668.html

11
nobeh

別の解決策は、静的なIntUnaryOperator.identity()を開始点として使用することです。

_IntUnaryOperator.identity().andThen(v -> v - 1).andThen(i -> i * 2)
_

静的インポートでは、identity()だけを使用することもできます。

IntUnaryOperatorに次のような静的メソッドがある場合...

_static IntUnaryOperator first(IntUnaryOperator op) { return op; }
_

...私たちは簡単に書くことができます:

_IntUnaryOperator.first(v -> v - 1).andThen(i -> i * 2)
_
11
isnot2bad