nickotaのあうとぷっと。

ため込むだけだった情報を世に発信する。

Udemy 「JavaSE8 インタフェース ラムダ式 ストリーム 集中コース」セクション3

セクション3 インタフェース

関数型インターフェース:SE8から追加された機能

関数型インターフェースの特徴

  • 抽象メソッドは1個のみ
  • インターフェースの名称と抽象メソッドの名称が1対1で対応している
  • シグニチャ(戻り値と引数)によって処理内容の概要が決定される
  • 関数型インターフェースのオブジェクト化を「抽象メソッドを実装する」方法で実現可能

レクチャー01 SE7までのインタフェースの特徴

  • 複数個の抽象メソッドが設定可能
  • 継承にて利用されるのが一般的
  • 定数はpublic static扱いになる
  • オブジェクトにはなれない
  • プログラミングよりも設計段階にて利用される
public interface Se7Interface {
    // 定数(public static は省略可。)
    public static int fromHeiseiYear = 1898;

    // 抽象メソッド(abstract は省略可。)
    abstract String getData(String data);
    abstract Integer getInteger(Integer integer);
}

Se7Interfaceは抽象メソッドを複数持つため関数型インターフェースではない。

SE7→SE8の変更点:オプジェクトになることができる(new ~~Interface)

レクチャー02 SE8インターフェースの特徴

  • 複数の静的(static)メソッドが設定可能
  • 複数個のdefaultメソッドが設定可能
  • 複数個の抽象メソッドが設定可能

 (利用時:実装化か必須)
 (再確認:関数型インターフェースの抽象メソッド数は1個

  • new演算子によるオブジェクト生成が可能
  • 関数型インターフェースはSE8インターフェースにおける一つの特殊な形態である。

レクチャー03 インターフェースのまとめ

f:id:nickota:20200108151421p:plain

レクチャー04 SE8を利用したサンプルプログラム

Java7までは匿名クラスを作るか、インターフェースを実装したクラスを作るしかなかった。

public interface SampleInterface {
    // 静的メソッド
    static void printStatic() {
        System.out.println("静的メソッド");
    }
    // defaultメソッド
    default void printDefault() {
        System.out.println("Defaultメソッド");
    }
    // 抽象メソッド
    abstract void printAbstract(String inStr);

    // 実装されているメソッド → コンパイルエラー
    //    void printMethod() {
    //        System.out.println("実装されているメソッド");
    //    }
}
public class S03L04 {
    public static void main(String[] args) {
        // 静的メソッドはnewしなくても実行可能
        SampleInterface.printStatic();
        // 抽象メソッドが未オーバーライドなのでコンパイルエラー
        // SampleInterface si1 = new SampleInterface(){};

        // 匿名クラスを用いたオブジェクト生成
        SampleInterface si2 = new SampleInterface() {
            @Override
            public void printAbstract(String inStr) {
                System.out.println(inStr);
            }
        };
        // defaultメソッドの実行
        si2.printDefault();
        // オーバーライドされたメソッドの実行
        si2.printAbstract("オーバーライドされた抽象メソッド");
        // S03L0402オブジェクトにて実行
        S03L0402 s = new S03L0402();
        s.printAbstract("オーバーライドされた抽象メソッド2");
    }
}

class S03L0402 implements SampleInterface {
    @Override
    public void printAbstract(String inStr) {
        System.out.println(inStr);
    }
}

レクチャー05 関数型インターフェース

@FunctionalInterface
public interface CheckWonLottery {
    // 抽象メソッド
    abstract public String check(Integer inNnumber, Integer winNumber);
}

[補足事項]

  1. @FunctionalInterface:関数型インタフェースを意味するアノテーション
  2. abstract:抽象メソッドを意味する、省略可能
  3. 静的メソッド、defaultメソッドの有無には捕らわれない

[構文解説]
シグニチャ:
引数:二個のInteger、戻り値:String

[関数型インタフェースの特徴]
CheckWonLotteryとcheck(抽象メソッド)が1対1に対応している

レクチャー06 関数型インタフェースのオブジェクト生成と利用方法

public class S03L06 {
    public static void main(String[] args) {
        CheckWonLottery cw = new CheckWonLottery() {
            @Override
            public String check(Integer n1, Integer n2) {
                if (n1 == n2) return "的中";
                else return "外れ";
            }
        };
        String result = cw.check(10555, 105559);
        System.out.println(result); // 外れ
    }
}

注意:

  1. check(Integer n1, Integer n2)で”int” のような基本型は使わないと覚えておく。
  2. “CheckWonLottery” のような特定の場合だけに使うような名前は避ける。より寛容的な名前をつけよう。

レクチャー07 SE8にて利用できる主な関数型インタフェース一覧

f:id:nickota:20200108152638p:plain

これらのインタフェースはJava8から組み込まれている。普通に使って良い。
それぞれのシグニチャはバラバラ。

新たな関数型インタフェースを作ることは稀。
適切なものを上記から選んで使うのが好ましい。

レクチャー08 関数型インタフェースJavaAPIドキュメントの参照方法

!!!!JavaAPIは見る癖をつけましょう!!!!!
Consumer インタフェースのAPI参照する。
andThenというメソッドがあるからどのような挙動か確認してみる。

import java.util.function.Consumer;

public class S03L08 {
    public static void main(String[] args) {
        // 構文:abstract void accept(T t)
        Consumer<String> cs1 = new Consumer<String>() {
            @Override
            public void accept(String inStr) {
                System.out.println("cs1" + inStr);

            }
        };
        cs1.accept("の実行");

        Consumer<String> cs2 = new Consumer<String>() {
            @Override
            public void accept(String inStr) {
                System.out.println("cs2" + inStr);

            }
        };
        cs2.accept("の実行");

        Consumer<String> cs3 = cs1.andThen(cs2);
        System.out.println("以下、cs3の実行結果");
        cs3.accept("の実行"); // cs1とcs2のオブジェクトが連続実行
    }
}


次回から今まで書いた匿名クラスをラムダ式に変換していく。