ラムダ式
1.ラムダ式の背景
ラムダ式は、JDK1.8の重要な新機能です。
ラムダ式を使用すると、関数型インターフェースを式に置き換えることができます。ラムダ式はメソッドと同じように、通常のパラメーターリストと、それらのパラメーターを使用する本体(本体、式またはコードブロックの場合があります)を提供します。
ラムダ式は、数学のラムダ計算にちなんで名付けられた無名関数と見なすことができ、クロージャと呼ぶこともできます。
1.1ラムダ式の構文
基本構文:(parameters)->expression 或 (parameters)->{statements;}
ラムダ式は3つの部分で構成されています:
- パラメータ:メソッドの正式なパラメータリストと同様に、ここでのパラメータは機能インターフェイスのパラメータです。ここでのパラメータータイプは、明示的に宣言することも宣言しないこともでき、JVMによって暗黙的に推測されます。また、推測されるタイプが1つしかない場合は、括弧を省略できます。
- ->:「に使用される」の意味として理解することができます
- メソッド本体:これは、関数インターフェイスでのメソッドの実装である式またはコードブロックにすることができます。コードのブロックは値を返すことも、何も返さないこともできます。ここで、コードのブロックはメソッドのメソッド本体と同等です。式の場合は、値を返すことも、何も返さないこともできます。
// 1. 不需要参数,返回值为 2
() -> 2;
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x;
// 3. 接受2个参数(数字),并返回他们的和
(x, y) -> x + y;
// 4. 接收2个int型整数,返回他们的乘积
(int x, int y) -> x * y;
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s)->System.out.print(s);
1.2機能インターフェイス
機能インターフェイスの定義: インターフェイスには、1つだけの抽象メソッドがあります。
知らせ:
- 抽象メソッドが1つしかない場合、インターフェースは機能インターフェースです。
- インターフェイスで@FunctionalInterfaceアノテーションを宣言すると、コンパイラは機能インターフェイスの定義に従ってインターフェイスを要求するため、2つの抽象メソッドがある場合、プログラムのコンパイルでエラーが報告されます。したがって、ある意味で、インターフェースに抽象メソッドが1つしかないことを保証する限り、このアノテーションはそのままにしておくことができます。さらに、それは自動的に検出されます。
によって定義されます:
@FunctionalInterface
interface NoParameterNoReturn {
void test(); // 只能有一个抽象方法
}
別の方法:
@FunctionalInterface
interface NoParameterNoReturn {
void test(); // 只能有一个抽象方法
default void test2(){
System.out.println("111");
}
}
2.ラムダ式の基本的な使用法
2.1戻り値もパラメーターもありません
//无返回值无参数
@FunctionalInterface
interface NoParameterNoReturn {
void test();
}
public class Test {
public static void main2(String[] args) {
//无返回值无参数
NoParameterNoReturn parameterNoReturn = ()-> System.out.println("重写方法");
}
}
2.2戻り値のない1つのパラメーター
// 无返回值一个参数
@FunctionalInterface
interface OneParameterNoReturn {
void test(int a);
}
public class Test {
public static void main(String[] args) {
//无返回值有一个参数
OneParameterNoReturn oneParameterNoReturn = (a)->{
System.out.println(a);};
oneParameterNoReturn.test(10);
OneParameterNoReturn oneParameterNoReturn1 = a-> System.out.println(a);
oneParameterNoReturn1.test(10);
OneParameterNoReturn oneParameterNoReturn2 = System.out::println;
oneParameterNoReturn2.test(10);
}
}
2.3戻り値のない複数のパラメーター
//无返回值多个参数
@FunctionalInterface
interface MoreParameterNoReturn {
void test(int a,int b);
}
public class Test {
public static void main(String[] args) {
MoreParameterNoReturn moreParameterNoReturn = (a,b)->{
System.out.println(a+b);
};
moreParameterNoReturn.test(10,20);
MoreParameterNoReturn moreParameterNoReturn1 = (a, b) -> System.out.println(a+b);
moreParameterNoReturn1.test(20,30);
}
}
2.4戻り値あり、パラメーターなし
//有返回值无参数
@FunctionalInterface
interface NoParameterReturn {
int test();
}
public class Test {
public static void main(String[] args) {
NoParameterReturn noParameterReturn = ()->{
return 10;};
int ret = noParameterReturn.test();
System.out.println(ret);
NoParameterReturn noParameterReturn1 = ()->10;
int ret1 = noParameterReturn1.test();
System.out.println(ret1);
}
}
2.5戻り値を持つ1つのパラメーター
//有返回值一个参数
@FunctionalInterface
interface OneParameterReturn {
int test(int a);
}
public class Test {
public static void main(String[] args) {
OneParameterReturn oneParameterReturn = (a) -> {
return a+11;};
int ret = oneParameterReturn.test(10);
System.out.println(ret);
OneParameterReturn oneParameterReturn1 = a -> a+11;
System.out.println(oneParameterReturn1.test(10));
}
}
2.6戻り値を持つ複数のパラメーター
//有返回值多参数
@FunctionalInterface
interface MoreParameterReturn {
int test(int a,int b);
}
public class Test {
public static void main(String[] args) {
MoreParameterReturn moreParameterReturn = (a,b) -> {
return a+b;};
moreParameterReturn.test(10,20);
MoreParameterReturn moreParameterReturn1 = (a,b) -> a+b;
System.out.println(moreParameterReturn1.test(30,40));
}
}
2.7PriorityQueueの使用例
2.8構文の簡略化
- パラメータタイプは省略できますが、省略したい場合は各パラメータのタイプを省略してください。
- パラメーターの括弧内にパラメーターが1つしかない場合は、括弧を省略できます。
- メソッド本体にコードが1行しかない場合は、中括弧を省略できます。
- メソッド本体にreturnステートメントであるステートメントが1つしかない場合は、中括弧を省略して、returnキーワードを削除できます。
3.変数キャプチャ
ラムダ式には変数キャプチャがあります。変数キャプチャを理解すると、ラムダ式のスコープをよりよく理解できます。Javaの匿名クラスでは、変数キャプチャがあります。
3.1匿名内部クラスの変数キャプチャ
class Test1{
public void func(){
System.out.println("func");
}
}
public class TestDemo {
public static void main(String[] args) {
int a = 100;
new Test1(){
@Override
public void func() {
System.out.println("内部类,重写了func方法");
System.out.println("捕获变量, 要么是常量,要么未发生的变量" + a);
}
}.func();
}
}
上記のコードの変数aは、キャプチャされた変数です。この変数はfinalによって変更されます。finalによって変更されていない場合は、使用する前に変更されていないことを確認する必要があります。
悪い例1:
悪い例2:
3.2ラムダの可変キャプチャ
@FunctionalInterface
interface NoParameterNoReturn {
void test();
}
public static void main(String[] args) {
int a = 10;
NoParameterNoReturn noParameterNoReturn = ()->{
// a = 99; error
System.out.println("捕获变量:"+a);
};
noParameterNoReturn.test();
}
4.コレクションでのLambdaの使用
LambdaとJavaのコレクションクラスをより適切に設定するために、Lambda式とドッキングするためのいくつかの新しいインターフェイスがコレクションに追加されました。
対応するインターフェース | メソッドを追加 |
---|---|
コレクション | removeIf() spliterator() stream() parallelStream() forEach() |
リスト | replaceAll() sort() |
地図 | getOrDefault() forEach() replaceAll() putIfAbsent() remove() replace() computeIfAbsent() computeIfPresent() compute() merge() |
4.1収集インターフェース
forEach()
メソッド
のデモンストレーション使用例:
class Test1{
public void func(){
System.out.println("func");
}
}
public class TestDemo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("ze");
list.add("www");
list.add("qwer");
list.add("lambda");
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
list.forEach(s-> System.out.println(s));
}
}
4.2リストインターフェース
sort()
メソッドのデモンストレーション
使用例:
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("ze");
list.add("www");
list.add("qwer");
list.add("lambda");
list.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length()-o2.length();
}
});
System.out.println(list);
list.sort((o1, o2) -> o1.length()-o2.length());
System.out.println(list);
}
4.3マップインターフェース
forEach()
メソッド
コードの例:
public static void main(String[] args) {
HashMap<Integer,String> map = new HashMap<>();
map.put(1,"ze");
map.put(2,"www");
map.put(3,"qwer");
map.put(4,"lambda");
map.forEach(new BiConsumer<Integer, String>() {
@Override
public void accept(Integer integer, String s) {
System.out.println("key:"+integer+"value:"+s);
}
});
map.forEach((key,value)-> System.out.println("key:"+key+"value:"+value));
}
5.まとめ
ラムダ式の利点は明らかです。コードレベルでは、コードは非常に簡潔になります。欠点も明らかで、コードは読みにくいです。
アドバンテージ:
- シンプルなコード、迅速な開発
- 便利な関数型プログラミング
- 並列化が非常に簡単
- Javaは収集操作を改善するためにLambdaを導入します
欠点:
- コードの可読性が低い
- 非並列コンピューティングでは、多くの計算のパフォーマンスが従来よりも高くない場合があります。
- デバッグするのは簡単ではありません