Java Silver SE11 8章
黒本をもとに学んだことをアウトプットしていきます。
主に問題を解いていて、間違えた箇所もしくは知らなかった内容になります。
関数型インタフェース
実装が必要なメソッドを1つだけ持つインタフェースのこと。
抽象メソッドを1つだけ持つので、後に記述するラムダ式が「どのメソッドを実装するのか」必然的に決めることができる。
@FunctionalInterface
アノテーションを付与することで、明示することも可能。
ラムダ式
簡単なインタフェースでも新しくクラスを作成する必要がある。
この問題を新しくクラスを作る代わりに、ラムダ式に置き換えることができる。
ルール
- 関数型インタフェースを使う
- 実行したい処理が1つのみの場合は、「()」「{}」も省略可能
- また省略した場合、戻り値を戻すにはreturnを記述できない
- メソッド内のローカル変数と同じ名前の変数を、ラムダ式内で宣言できない
- 実施的なfinalな変数でなければ、ラムダ式内から外の変数ヘはアクセスできない
- ラムダ式は宣言されたタイミングで使用されるわけではないので、宣言後に変数を変更されると意図しない動作をする可能性がある
構文
関数型インタフェースの型 変数名 = (引数) -> {処理};
例1
public class Main {
public static void main(String[] args) {
// {}がある場合は、returnは省略できない
Function f = (name) -> {
return "hello" + name;
};
// 処理が1つかつ{}がない場合は、returnを記述できない
Function f2 = (name) -> "hello " + name;
System.out.println(f.test("Lambda")); // hello Lambda
System.out.println(f2.test("Lambda2")); // hello Lambda2
}
private static interface Function {
String test(String name);
}
}
例2
public class Main {
public static void main(String[] args) {
String str = "A";
Function f = (val) -> {
System.out.println(val);
};
f.test(str); // A
f.test("B"); // B
// コンパイルエラー
// Function f2 = (str) -> {
// System.out.println(str);
// };
}
}
interface Function{
void test(String val);
}
Function f2 = (str) -> {
は、String str = "A";
を再定義しようとしている
例3
public class Main {
public static void main(String[] args) {
int cnt = 0;
Runnable r = () -> {
for (cnt = 0; cnt < 10; cnt++) {
System.out.println(cnt++);
}
};
new Thread(r).start(); // コンパイルエラー
}
}
ラムダ式内で10回処理するだけなら、for (int cnt = 0; cnt < 10; cnt++) {
と変更することで「02468」と表示させることができる。
java.util.functionパッケージ
頻繁に使われる関数型インタフェースは、java.util.functionパッケージに記述されている。
例:Consumer
「消費者」, Supplier
「供給者」, Predicate
「断定」, Function
「処理」 など
関数型インタフェース | メソッド | 内容 |
---|---|---|
Consumer<T> | void accept(T) | 引数を受け取り、処理を実行(戻り値なし) |
Supplier<T> | T get() | 引数を受け取らず、戻り値を返す |
Predicate<T> | boolean test(T) | 引数を受け取り、判定を返す |
Function<T, R> | R apply(R) | 引数を受け取り、戻り値(R)を返す |