web-dev-qa-db-ja.com

ラムダ式と静的メソッド

コードの重複がないラムダ式の再利用性について質問がありました。たとえば、ヘルパーメソッドがある場合、静的メソッドとして簡単にコーディングでき、コードを重複させることなく他のクラスから参照できます。これはラムダ式でどのように機能しますか?例:次の静的メソッドを記述しています

public class MyUtil {

    public static int doubleMe(int x) {
        return x * 2;
    }
}

プロジェクト全体の複数の場所でコードを重複させることなく、同じメソッドを再利用できます

public class A {

    public void someOtherCalculation() {
        MyUtil.doubleMe(5);
    }
}

public class B {

    public void myCalculation() {
        MyUtil.doubleMe(3);
    }
}

ラムダ関数に関しては、どのように機能しますか。関数を1回記述し、複数のクラスで同じものを使用します。

Function<Integer, Integer> doubleFunction = x -> x * 2;

私の例では、上記のラムダ関数をどこに記述し、クラスAとBで同じものをどのように再利用しますか?

10
Nova Guy

上記のラムダ関数はどこに書きますか

関数はフィールドを参照しないため、静的な最終フィールドに配置するのが適切です。

class Utility {
    public static final Function<Integer,Integer> doubleFunction = x -> x * 2;
}

クラスAとBで同じものをどのように再利用しますか?

これをUtility.doubleFunctionと呼び、必要なコンテキストで渡します。

callMethodWithLambda(Utility.doubleFunction);

メソッド参照を使用すると、関数を定義して、ラムダであるかのように使用できることに注意してください。

class Utility {
    public static Integer doubleFunction(Integer x) {
        return x*2;
    }
}
...
callMethodWithLambda(Utility::doubleFunction);

このアプローチは、必要に応じて複数のコンテキストで同じコードを再利用できるため、非常に柔軟性があります。

8
dasblinkenlight

実際、無名関数はコードの再利用が必要な場合のためのものですそうではありません

ばかげた例ですが、mapを使用してリスト内のすべての数値に2を追加しているとします。これがあらゆる場所で必要になる可能性のある一般的なアクションである場合、数値に2を加算する静的関数は、どこにでも同じラムダを書き込むよりも理にかなっています。

ただし、リストに2つを追加する単一の関数がある場合は、「2つ追加」関数をローカルでラムダとして定義する方が理にかなっているため、他の場所で必要のないコードでクラスをプラグインしないでください。

高階関数を多用するClojureを作成する場合、作成している「フル」関数のコードを整理するローカル無名関数を作成することは非常に一般的です。これらの無名関数の大部分は、「グローバル」スコープ(またはクラススコープ)では無意味です。特に、通常はローカル変数をクロージャしているため、とにかくグローバルにすることはできません。

3
Carcigenicate

他の答えとは異なります。 TDDの方法であなたの質問に答えたいと思います。

[〜#〜] if [〜#〜]あなたのdoubleMeはあなたが書いたようにとても単純です、それはあなたがやめるべきですメソッド式の参照を悪用し、一般的なメソッド呼び出しとして直接呼び出すだけです。

[〜#〜] if [〜#〜]doubleMeは非常に複雑なので、doubleMeをテストする必要があります独立している場合は、依存性注入によって暗黙的な依存関係を明示的に作成して、それらが累積プロトコルによって連携できるかどうかをテストする必要があります。しかし、JavaリフレクションAPIを使用する場合を除いて、メソッドを直接参照することはできません メソッド /[〜#を実装する匿名クラスを使用する〜] sam [〜#〜]jdk-8の前のメソッドにリクエストを委任するインターフェース。jdk-8の機能インターフェースへのメソッド式参照を参照できるのは嬉しいことです。 。したがって、機能インターフェイスを使用して暗黙的な依存関係を明示的にすることができるので、次のように通信プロトコルテストを記述します。

@Test
void applyingMultiplicationWhenCalculating???(){
    IntUnaryOperator multiplication = mock(IntUnaryOperator.class);
    B it = new B(multiplication);

    it.myCalculation();

    verify(multiplication).applyAsInt(3);
}

[〜#〜] and [〜#〜]すると、Bのようなクラスは、以下のようになります。

public class B {
    IntUnaryOperator multiplication;

    public B(IntUnaryOperator multiplication){
          this.multiplication = multiplication;
    }

    public void myCalculation() {
          multiplication.applyAsInt(3);
    }
}

[〜#〜] then [〜#〜]以下のように、関数型インターフェースへのメソッド式参照を参照することにより、メソッドを再利用できます。

A a = new A(MyUtil::doubleMe);
B b = new B(MyUtil::doubleMe);
2
holi-java

ラムダ式を使用すると、再利用性について心配する必要はありません(実際、ほとんどのラムダはまったく再利用されていません)。 Functionポインターでこのメソッドを指すようにする場合は、次のように宣言できます。

Function<Integer, Integer> doubleFunction = MyUtil::doubleMe;

そして、それを任意のメソッドまたはストリームに渡して、適用/マッピングします。例:

public static void consume(Function<Integer, Integer> consumer, int value){
    System.out.println(consumer.apply(value));
}

public static void main(String[] args) throws Exception{
    Function<Integer, Integer> doubleFunction = MyUtil::doubleMe;
    consume(doubleFunction, 5);
}
2
Darshan Mehta

あなたは以下のようなことをすることができます。

class Fn {
  public static final Function<Integer, Integer> X2TIMES = x -> x *2;
}

class Test {
  public static void main (String[] args) {
    System.out.println(Fn.X2TIMES.apply(5));
  }
}
0
Anil Bachola