36

Java8でメソッド参照をFunctionオブジェクトとして使用してそのメソッドを使用する方法はありますか?

Stream.of("ciao", "hola", "hello")
    .map(String::length.andThen(n -> n * 2))

この質問は とは関係ありませんStream。例として使用されています。メソッド リファレンスについて回答をお願いします。

4

7 に答える 7

32

これを行う静的メソッドを作成できます。

import java.util.function.*;

class Test {
    public static void main(String[] args) {
        Function<String, Integer> function = combine(String::length, n -> n * 2);
        System.out.println(function.apply("foo"));
    }

    public static <T1, T2, T3> Function<T1, T3> combine(
        Function<T1, T2> first,
        Function<T2, T3> second) {
        return first.andThen(second);
    }
}

次に、それをユーティリティ クラスに配置して、静的にインポートできます。

または、与えられた関数を返すだけの単純な静的メソッドを作成して、コンパイラが何をしているのかを認識できるようにします。

import java.util.function.*;

class Test {
    public static void main(String[] args) {
        Function<String, Integer> function = asFunction(String::length).andThen(n -> n * 2);
        System.out.println(function.apply("foo"));
    }

    public static <T1, T2> Function<T1, T2> asFunction(Function<T1, T2> function) {
        return function;     
    }
}
于 2015-08-25T14:08:09.797 に答える
11

キャストを使用して、インラインで目的を達成できるはずです。

Stream.of("ciao", "hola", "hello")
      .map(((Function<String, Integer>) String::length).andThen(n -> n * 2))

コンパイラには「タイプヒント」しかないため、実際にはオブジェクトを「キャスト」せず、実際のキャストのオーバーヘッドはありません。


または、読みやすくするためにローカル変数を使用できます。

Function<String, Integer> fun = String::length

Stream.of("ciao", "hola", "hello")
      .map(fun.andThen(n -> n * 2));

より簡潔な 3 つ目の方法は、ユーティリティ メソッドを使用することです。

public static <T, X, U> Function<T, U> chain(Function<T, X> fun1, Function<X, U> fun2)
{
    return fun1.andThen(fun2);
}

Stream.of("ciao", "hola", "hello")
      .map(chain(String::length, n -> n * 2));

これはテストされていないことに注意してください。したがって、この場合に型推論が正しく機能するかどうかはわかりません。

于 2015-08-25T14:04:46.073 に答える
8

使用することもできます

Function.identity().andThen(String::length).andThen(n -> n * 2)

問題は、String::length必ずしもFunction;ではないことです。多くの機能的インターフェースに適合できます。これは、ターゲット タイプを提供するコンテキストで使用する必要があり、コンテキストは代入、メソッド呼び出し、キャストなどです。

Functionターゲットの型付けのためだけに静的メソッドを提供できる場合は、次のことができます。

    Function.by(String::length).andThen(n->n*2)

static <T, R> Function<T, R> by(Function<T, R> f){ return f; }

たとえば、機能的なインターフェイスでこの手法を使用します

static <T> AsyncIterator<T> by(AsyncIterator<T> asyncIterator)

ラムダ式またはメソッド参照から AsyncIterator を作成する構文シュガー。

このメソッドは単に引数 を返しますがasyncIterator、これは少し奇妙に思えます。説明:

AsyncIterator は関数型インターフェースであるため、インスタンスはラムダ式またはメソッド参照によって 3 つのコンテキストで作成できます。

 // Assignment Context
 AsyncIterator<ByteBuffer> asyncIter = source::read;
 asyncIter.forEach(...);

 // Casting Context
 ((AsyncIterator<ByteBuffer>)source::read)
     .forEach(...);

 // Invocation Context
 AsyncIterator.by(source::read)
     .forEach(...);

3 番目のオプションは他の 2 つよりも見栄えがよく、それがこの方法の目的です。

于 2015-08-25T14:55:04.843 に答える
5

キャストを使用できます

Stream.of("ciao", "hola", "hello")
        .map(((Function<String, Integer>) String::length)
                .andThen(n -> n * 2))
        .forEach(System.out::println);

版画

8
8
10
于 2015-08-25T14:07:56.773 に答える