JavaSilverに向けて⑩ ラムダ式
・ラムダ式
クラスの宣言とインスタンスの生成を同時に行う文法。
ー ラムダ式のメリット
関数型インターフェースを実装するためのソースを短く書ける。
Stream APIの引数としての関数型インターフェースを記述するのに適している。
*関数型インターフェース
抽象メソッドを1つ持つインターフェースの事。
*Stream API
配列やList, Collectionなどの要素の集合に対して、要素の直列処理や並列処理、要素の比較並び替え、一致判定などの処理を実行するメソッド群の事。
・ラムダ式の使い方
インターフェース名 オブジェクト名 = (引数1, 引数2, •••) -> {return 処理内容};
上記が、ラムダ式の基本的な形である。また、上記では型の記述がないが、型を記載してもエラーにはならない。
ー ラムダ式の引数が1つの場合
インターフェース名 オブジェクト名 = 引数 -> 処理;
引数が1つの場合、処理結果を返すreturn句、{}、()を省略できる。
interface InterfaceSample {
String process();
}
public class Sample {
public static void main(String[] args) {
InterfaceSample s = () -> “hello”;
System.out.println(s.process());
}
}
ラムダ式の処理が1つしかなく、何らかの戻り値を戻す場合は、return句を省略できるというよりも省略しなければならない。
上記の例を基に考えるのであれば、以下のようにreturn句を書くとコンパイルエラーとなる。
public class Sample {
public static void main(String[] args) {
InterfaceSample s = () -> return “hello”; //コンパイルエラー
System.out.println(s.process());
}
}
また、戻り値を戻すメソッドで、その処理を{}で括った場合、return句を記述しなければならず、return句を記述しなければコンパイルエラーとなる。
public class Sample {
public static void main(String[] args) {
InterfaceSample s = () -> { “hello”;}; //コンパイルエラー
System.out.println(s.process());
}
}
・関数型interfaceの実装をラムダ式に置き換える方法
interface InterfaceTest {
public String method(String name, int n);
}
public class Main {
public static void main(String[] args) {
InterfaceTest it = (name, n) -> {
return “Hello “ + name + n + “!”;
}
System.out.println(it.method(“Java”, 8);
}
}
・Stream APIの引数にラムダ式を使う方法
List, Collectionなどのオブジェクト名.stream().メソッド名((引数) -> {処理})
・ラムダ式でのforEach
以下では、メソッド参照(System.out::println)を使って短く記述する事ができる。
public class Main {
public static void main(String[] args) {
Integer[] num = {1,2,3,4,5};
List<Integer> l = Arrays.asList(num);
l.forEach(System.out::println);
}
}
・ラムダ式でのfilter
public class Main {
public static void main(String[] args) {
Integer[] num = {1,2,3,4,5};
List<Integer> l = Arrays.asList(num);
l.stream().filter(x -> x < 3).forEach(System.out::println);
}
}
・ラムダ式の特徴
ー ラムダ式内で変数の値の変更はNG
ラムダ式からローカル変数にアクセスする事が可能だが、そのラムダ式内でローカル変数を変更するとコンパイルエラーとなる。
interface InterfaceSample {
void test();
}
public class Sample {
public static void main(String[] args) {
String str = “hello”;
InterfaceSample s = () -> {
str = “hello, hello”; //コンパイルエラー
System.out.println(str);
};
s.test();
}
}
ー ラムダ式の外であっても変数の変更はNG
ラムダ式が宣言したタイミングで実行されるわけではないため、宣言後であっても変更されるとコンパイルエラーとなる。
public class Sample {
public static void main(String[] args) {
String str = "hello";
InterfaceSample s = () -> {
System.out.println(str);
};
str = "hello, hello"; //コンパイルエラー
s.test();
}
}
・Function<T,R> 引数ありで戻り値あり
FunctionのTはメソッドの引数の型、Rはメソッドの戻り値の型。applyメソッドが使える。
public class Sample {
public static void main(String[] args) {
Function <Integer, String> f = a -> a + "です";
String b = f.apply(2);
System.out.println(b); //2です
}
}
・Consumer<T> 引数ありで戻り値なし
ConsumerのTはメソッドの引数の型。acceptメソッドが使える。
public class Sample {
public static void main(String[] args) {
Consumer<Integer> c = a -> System.out.println(a + "です");
c.accept(3); //3です
}
}
・Predicate<T> 引数ありでbooleanの戻り値あり
PredicateのTはメソッドの引数の型。testメソッドが使え、booleanを戻す。
public class Sample {
public static void main(String[] args) {
Predicate<String> p = a -> a.isEmpty();
boolean b = p.test("a");
System.out.pritnln(b); //false
boolean c = p.test("");
System.out.println(c); //true
}
}
・Supplier<T> 引数なしで戻り値あり
SupplierのTはメソッドの戻り値の型。getメソッドが使える。getメソッドは引数はないが戻り値はある。
public class Sample {
public static void main(String[] args) {
Supplier<String> s = () -> "hello";
String a = s.get();
System.out.println(a); //hello
}
}
参照
https://engineer-club.jp/java-lambda-expression
https://www.sejuku.net/blog/22337
https://itsakura.com/java-lambda-function
この記事が気に入ったらサポートをしてみませんか?