メモっとけ Java 8 Lambdas 〜Chapter2〜

Java 8 Lambdas: Pragmatic Functional Programming (English Edition)

Java 8 Lambdas: Pragmatic Functional Programming (English Edition)

  • 作者:Richard Warburton
  • 出版社/メーカー: O'Reilly Media
  • 発売日: 2014/03/18
  • メディア: Kindle版
        

関数型プログラミングスタイルによって何が変わるかというと、
The difference is that object-oriented programming is mostly about abstracting over data, while functional programming is mostly about abstracting over behavior.
        

ラムダ式

Swing のアクションリスナーに匿名クラスでActionListenerの実装を入れる例

    button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent event) {
            System.out.println("button clicked.");
        }
    }

     

ラムダ式を使うと以下のように書ける。

    button.addActionListener(event -> System.out.println("button clicked."));

        

さらに色々な例

引数なしの関数定義で、Runnable インターフェースの唯一の引数なしメソッド run を定義

    Runnable noArguments = () -> System.out.println("Hello World.");

        

複数の文が必要な場合は {} で囲む

    Runnable multiStatement = () -> {
        System.out.println("Hello");
        System.out.println("World");
    }

     

引数が2つの関数定義

    BinaryOperator<Long> add = (x, y) -> x + y;

  

引数の型を指定した例

    BinaryOperator<Long> addEcplicit = (Long x, Long y) -> x + y;

        

クロージャではない

匿名クラスで外部の変数を参照するには変数宣言をfinalにする必要がある

    final String name = getUserName();
    button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent event) {
            System.out.println("Hello " + name);
        }
    }

     

ラムダ式だと以下のように書ける

    String name = getUserName();
    button.addActionListener(event -> System.out.println("Hello " + name));

     

ラムダ式内では変数ではなく値として取り込まれ、つまり暗黙的に final 宣言されたように振る舞う。 そして以下のようにすると「ラムダ式中の変数はfinalか事実上finalでないと駄目!」コンパイルエラーになる。

    String name = getUserName();
    name = formatUserName(name);
    button.addActionListener(event -> System.out.println("Hello " + name));

     

関数インターフェース

ラムダ式の型として使われる、1つの抽象メソッドが定義されたインターフェース 例えば先の例で見た ActionListener は昔からなじみのあるもの。

    public interface ActionListener extends EventListener {
        public void actionPerformed(ActionEvent e);
    }

     

JDK で提供されるよく使う関数インターフェース

Interface name Arguments Rerurns
Predicate<T> T boolean
Consumer<T> T void
Function<T, R> T R
Supplier<T> None T
UnaryOperation<T> T T
BinaryOperation<T> (T, T) T

     

Predicate は1つの引数を入力として、boolean を返す関数。定義は以下。

    public interface Predicate<T> {
        boolean test(T t);
    }

     

5 より大きいかを判断する関数。

    Predicate<Integer> atLeast5 = x -> x > 5;

     

BinaryOperation は2つの引数を入力として1つの出力を返す関数。

    BinaryOperation<Long> addLongs = (x, y) -> x + y;

  

以下のようにするとコンパイルエラーとなる。

    BinaryOperation addLongs = (x, y) -> x + y;

  

UnaryOperation は論理否定。

        

ThreadLocal の withInitial() は Supplier 関数を引数に取るので以下のような初期化コードが可能。

    public final static ThreadLocal<SimpleDateFormat> formatter = ThreadLocal.withInitial(
        () -> new SimpleDateFormat("dd-MMM-yyyy") );

     

次回

blog1.mammb.com

に続く