技術とか戦略とか

IT技術者が技術や戦略について書くブログです。

java:関数を引数として渡す

C#では、こちらの記事のようにdelegateの仕組みを利用して関数を変数として扱うことができます。
例えば、引数と引き渡してコールバック処理を実現することができます。
 
javaでも、8以降であれば関数型インターフェースを利用して関数を変数として扱うことができます。
以下、サンプルコードです。
 
【サンプルコード】
・FunctionMain.java
import java.util.function.Function;

public class FunctionMain {
  public static void main(String args) {

    // Function型の変数の定義
    // 変数の中身はFunctionMainクラスのmakeEndMessage関数
    Function<String, String> function = FunctionMain::makeEndMessage;

    // 関数を引数として渡す
    somethingFunc(function);
  }

  public static void somethingFunc(Function<String, String> endFunc) {
    System.out.println("DoSomething");
    // 引き渡された関数を実行
    System.out.println(endFunc.apply("Something"));
  }

  // 今回引き渡す関数
  public static String makeEndMessage(String s) {
    return "End" + s;
  }

}
 
【実行結果】
DoSomething
EndSomething
 
-----------------
 
上記のようにFunction型を用いるのが基本的な形なのですが、いくつか発展的な記法が存在します。
 
例えば、引数と戻り値が同じ型である場合は、UnaryOperator型を使用することでジェネリクスの表記を省略することができます。
(他にも、戻り値がvoidの場合に適用できるConsumer型、戻り値がboolean型の場合に適用できるPredicate型等が存在します)
 
また、引き渡す関数をラムダ式で表記することで、関数の定義を省略することができます。
 
【サンプルコード】
・FunctionMain.java
import java.util.function.UnaryOperator;

public class FunctionMain {
  public static void main(String args) {

    // 引数と戻値が同じ場合はUnaryOperatorで簡略化できる
    // ラムダ式で関数の記述を簡略化できる
    UnaryOperator<String> function = (x) -> {return "End" + x;};

    somethingFunc(function);
  }

  public static void somethingFunc(UnaryOperator<String> endFunc) {
    System.out.println("DoSomething");
    System.out.println(endFunc.apply("Something"));
  }

}
 
【実行結果】
DoSomething
EndSomething