システムデザイン

【Java 8】5分でわかる関数型プログラミング

*本記事は旧TechblogからCOLORSに統合した記事です。

Java 8 以降では、新しく「関数型プログラミング」の考え方が導入され、その実現手法として「ラムダ式」「ストリームAPI」などが登場しました。

この記事では、Java未経験、Java初心者の方にもわかりやすい内容で、「関数型プログラミング」の概念の説明を行います。

目次

  1. 関数型プログラミング、その前に…
    1.1. インタフェースの考え方のおさらい
    1.2. インタフェースの考え方のおさらい(実装)
  2. 関数型プログラミング
    2.1. 機能拡張時の課題
    2.2. 関数型プログラミングの利用例
    2.3. 関数型プログラミングとは
  3. まとめ

1. 関数型プログラミング、その前に…

今回解説する「関数型プログラミング」の理解には、Javaでは基礎的な概念である「インタフェース」の理解が必須です。
そのため、まず「インタフェース」のおさらいから始めます。

1.1. インタフェースの考え方のおさらい

Javaにおけるインタフェースとは、処理の呼び出し側と、処理の実装を分離する考え方です。
 例えば、一般的な家庭にある「コンセント」も、インタフェースの例の一つです。
 コンセントの利用者は、コンセントの裏側でどんなことをしているのか理解していませんが、コンセントにプラグを刺すだけで、電気を利用 (送電という機能を利用) できます 。

Java8 インタフェースの概念例

このコンセントの例を、プログラムの処理の概念に置き換えた図が以下です。
 利用者は、発電所の内部で何を行っているのかは知りませんが、発電所が公開しているインタフェース(コンセント)に必要なパラメータを渡す(プラグを刺す)だけで、発電所の送電機能を利用できます。

Java8 プログラムよりなインタフェースの概念例

1.2. インタフェースの考え方のおさらい(実装)

Javaのインタフェースのサンプルコードを以下に記します。
 以下のサンプルコードでは、「例外処理機能」が登場します。
「例外処理機能」 は、利用者に対して、例外処理のインタフェースを公開しており、例外処理インタフェースの処理実装では「ログ出力」を行っています。

 Javaでのインタフェース使用例
/**
 * 「例外処理機能」が公開する例外処理インタフェース
 */
public interface SampleExceptionHandleInterface {
    /**
     * 例外処理メソッド
     *
     * @param exception 発生例外
     */
    void handleException(Exception exception);
/**
 * 「例外処理機能」が公開する例外処理インタフェースの処理実装
 */
public class SampleExceptionHandleImpl
        implements SampleExceptionHandleInterface {
    @Override
    public void handleException(Exception exception) {
        // 「ログ出力」を行う
        System.out.println(exception.getMessage());
    }
/**
 * 利用者
 */
public static void main(String[] args) {
    try {
    } catch (Exception exception) {
        // 例外処理インタフェースを利用する
        SampleExceptionHandleInterface exceptionHandler = new SampleExceptionHandleImpl();
        // 例外処理インタフェースに、発生した例外をパラメータとして連携する
        exceptionHandler.handleException(exception);
    }
}

2. 関数型プログラミング

2.1. 機能拡張時の課題

1.2の例外処理インタフェースの例を使用して、関数型プログラミングの説明を行います。
 1.2で登場した例外処理インタフェースを利用する業務Aと、業務Bが存在するとします。
 この時、業務Aは例外処理として、「ログ出力」の他に、「顧客へのメール送信」も行いたいという要求があり、
 業務Bは「ログ出力」の他に、「DBのステータス更新」も行いたいという要求があるとします。

 この場合、現状の例外処理インタフェースを使用した処理では業務側の要求を満たせないため、機能拡張を行う必要があり、また、例外処理インターフェースの処理実装では、業務Aと業務Bを意識した処理を行う必要が出てきます。

Java8 機能拡張時の課題

2.2. 関数型プログラミングの利用例

この課題の対応策として、いくつか方法は考えられますが、
ここで、 例外処理 インタフェース が、パラメータとして「業務側で実行したい処理」を受け取ることができるとすればどうなるでしょうか。

 例えば、業務Aからは、パラメータとして、「発生した例外」と「顧客へのメール送信の処理 」 を受け取り、処理の実装では、ログ出力を行った後、パラメータから受け取った「顧客へのメール送信」の処理を実行します。

 また、業務Bからは、パラメータとして、「発生した例外」と「DBのステータス更新の処理 」 を受け取り、 処理の実装では、ログ出力を行った後、パラメータから受け取った「DBのステータス更新」の処理を実行します。

 このように、インタフェースのパラメータとして、 「業務側で実行したい処理」 を渡してやることができれば、実装側の機能拡張を毎回行う必要が無く、呼び出し元ごとの要求に応じることができます。

Java8 パラメータによる処理実装の受け渡し

2.3. 関数型プログラミングとは

関数型プログラミングとは、 2.2の例の通り、メソッドの引数や戻り値に、「処理実装」(関数)を引き渡すことができるプログラミング思考です。
この考え方を実装に取り入れることで、2.2のような課題解決方法を採択することができるようになります。

(※注:ここではあくまで概念的な理解を促進するために、狭義な定義をしています)

3. まとめ

「5分でわかる関数型プログラミング」は、ここまでとなります。
 この記事では、インタフェースのおさらいから、関数型プログラミングの概念までを解説しました。
 続編の記事では、Javaのサンプルコードをまじえて、関数型プログラミングの考え方を実現する「ラムダ式」、また「ラムダ式」を活用する「ストリームAPI」の解説を行う予定ですので合わせてお読みいただければ幸いです。