エンジニア男

勉強したことの忘備録としてつらつら書いていきます。

【Java】関数型まとめ

関数型の書き方のメモ。

 

ラムダ式

ラムダ式」とは、メソッド定義を式として記述できる言語機能。

基本文法:「引数部 -> 処理本体」という形式で表す。

ラムダ式をメソッド単体の定義として見なせば、文法はそこまで難しくない。

引数部       → メソッドの仮引数

処理本体   → メソッド本体

 

ラムダ式の使い方

/**
* forEach()メソッドはIterableインターフェースのメソッド default void forEach(Consumer<? super T> action)を実装したクラスで使用できる
* 引数の Consumer は void accept(T t) を持つ関数型インターフェース
* (何か引数を受け取り、値を返さない処理を行う)
*/
List<String> fruits = Arrays.asList("ばなな", "みかん", "りんご")
fruits.forEach(f -> System.out.prinln(f));
// 出力結果:
// ばなな
// みかん
// りんご


// ラムダ式構文: 引数部
() -> { 処理本体 } // 引数が0個の場合
(str) -> { 処理本体 } // 引数が1個の場合
str -> { 処理本体 } // 引数が1個の場合は括弧の省略可
(str, n) -> { 処理本体 } // 引数が2個の場合
(String str, int n) -> { 処理本体 } // 型は推論されるので不要だが、記述してもOK


// ラムダ式構文: 処理本体
str -> System.out.println(str) // 処理が一文の場合、returnも波括弧も不要

// 波括弧を使って複数の処理を記述
// 戻り値が必要な関数型インターフェースは、returnを記述
str -> {
System.out.println(str);
return str.isEmpty();
}

 

 

 

・メソッド参照

「メソッド参照」とは、すでに定義済みのメソッドを、引数なしで呼び出せる言語機能。

基本文法:

staticメソッドを参照:「クラス名::メソッド名」

インスタンスメソッドを参照:「変数::メソッド名」

という形式で表す。 

 

List<String> fruits = Arrays.asList("ばなな", "みかん", "りんご")
fruits.forEach(System.out::println);
// 出力結果:
// ばなな
// みかん
// りんご

 

 

 

・コンストラクタ参照

「コンストラクタ参照」とは、メソッド参照と同じようにクラスのコンストラクタを参照することで、戻り値としてオブジェクトを返す。

基本文法:「クラス名::new」という形式で表す。

 

Supplier<List<String>> supplier = ArrayList::new;
List<String> sushiList = supplier.get();

sushiList.add("サーモン");
sushiList.add("いくら");
sushiList.add("マグロ");

sushiList.forEach(System.out::println);
// 出力結果:
// サーモン
// いくら
// マグロ


 

 

 

・関数型インターフェース

「関数型インターフェース」とは、抽象メソッドを1つだけ持つインターフェースのこと。

 

・標準関数型インターフェース

「標準関数型インターフェース」は、java.util.functionパッケージで定義されている。

TやRは型変数で、任意の参照型のインスタンスが代入される。

例: Function<String, Integer>

 

インターフェース 抽象メソッド メソッドの型の説明
Function<T, R> R apply(T t) 入力がT型オブジェクト、出力がR型オブジェクト
Predicate<T> boolean test(T t) 入力がT型オブジェクト、出力がboolean値
Consumer<T> void accept(T t) 入力がT型オブジェクト、出力無し
Supplier<T> T get() 入力なし、出力はT型オブジェクト

 

 ラムダ式を標準関数型インターフェース型変数に代入。

// Functionは入力Tを受け取り、出力Rを返す
Function<String, StringBuilder> strToStrBidr = s -> new StringBuilder(s);
StringBuilder alpha = strToStrBidr.apply("abc");
alpha.append("defg");
System.out.println(alpha.toString()) // 出力結果 : abcdefg

======
//Predicateは入力Tを受け取り、真偽値を返す。 条件式: nullではない かつ 空文字ではない
Predicate<String> isValidString = s -> Objects.nonNull(s) && !s.isEmpty()
// 出力結果
System.out.println(isValidString.test("")); // false
System.out.println(isValidString.test(null)); // false
System.out.println(isValidString.test("aaa")); // true


======
// Consumerは入力Tを受け取り何か(一般的に副作用のある)処理をする。出力は無い。
Consumer<String> proc = s -> System.out.println(s);
proc.accept("寿司") // 出力結果 : 寿司


======
// Supplierは入力なしで、出力Tを返す
Supplier<StringBuilder> factory = () -> new StringBulder();
StringBuilder jp = factory.get();
jp.append("日本");
System.out.println(jp.toString()) // 出力結果 : 日本
 

 

 

~~~ 随時更新 ~~~