1.ラムダの最初の知識
Javaでは、インターフェイスをインスタンス化することはできませんが、インターフェイスオブジェクトはその実装クラスオブジェクトを指すことができます。インターフェイスに実装オブジェクトさえない場合はどうなりますか?次に、次のように匿名クラスを使用することもできます。
public class JavaTest {
public static void main(String[] args) {
Fly fly = new Fly() {
@Override
public void fly(String name) {
System.out.println(name + "飞行");
}
};
fly.fly("张三");
}
}
interface Fly{
abstract void fly(String name);
}
ただし、匿名内部メソッドを使用すると、コードの量はそれほど簡潔ではありません。コードをより簡潔にするために、Javaは、Lambda式を使用して単純化することで、そのような関数を実現するために、より単純な構文でLambda式の記述メソッドを導入します。コードは次のように表示されます:
public class JavaTest {
public static void main(String[] args) {
Fly fly = name -> System.out.println(name + "飞行");
fly.fly("张三");
}
}
interface Fly{
abstract void fly(String name);
}
Lambda式でも同じ効果が得られますが、コードの量が非常に単純化されています。これがLambda式の魅力です。
2.機能インターフェイス
Lambda式の構文を学習する前に、まず関数型インターフェースとは何かを知っておく必要があります。実装するメソッドが1つしかないインターフェースは、関数型インターフェースと呼ばれます。
//接口中只有一个待实现的方法 fly,所以这是函数式接口
interface Fly{
void fly(String name);
}
//接口中有两个待实现的方法 这是不是函数式接口
interface Run{
void fastRun();
void slowRun();
}
//接口中有两个方法,但其中一个是已经定义好的default方法,真正需要子类去实现的方法只有一个 这是函数式接口
interface Jump{
void jump();
default void highJump(){
System.out.println("跳的更高");
}
}
インターフェイスに**@FunctionalInterfaceアノテーションを追加して、インターフェイスが機能インターフェイスであることを表明できます。インターフェイスが機能インターフェイスでない場合、コンパイルによりエラーが発生します。
機能的なインターフェイスとは何かを知っておく必要があるのはなぜですか?ラムダ式は匿名クラスがインターフェースを実装する方法を単純化するため、機能インターフェースでのみ機能します**。
これは理解しやすいです。インターフェイスに実装するメソッドが複数ある場合、ラムダ式はインターフェイスのどのメソッドを現在実装しているかを判断できません。
3.ラムダ式の構文
ラムダ式は、Java言語で演算子**“->” **を導入します。これは、ラムダ演算子またはアロー演算子と呼ばれます。ラムダを2つの部分に分割します。
左側:Lambda式に必要なすべてのパラメーターが指定されています
右側:Lambda本体、つまりLambda式によって実行される関数が指定されています。
このような:
(parameters) -> expression
或
(parameters) ->{ statements; }
Lambda式の->およびLambda本体に加えて、他のパラメーター、括弧、および角括弧は、パラメーターのタイプおよびメソッド本体のコードの行数に応じて省略できます。
例として、次の機能インターフェイスの実装を取り上げます。
interface MathOperation {
int operation(int a, int b);
}
interface GreetingService {
void sayMessage(String message);
}
private int operate(int a, int b, MathOperation mathOperation){
return mathOperation.operation(a, b);
}
interface NoParam{
int returnOne();
}
ラムダ式の重要な特性は次のとおりです。
- オプションの型宣言:ラムダ式は実装メソッドのパラメーター型を宣言する必要はなく、コンパイラーはパラメーター値を一律に識別できます。
// 类型声明
MathOperation addition = (int a, int b) -> a + b;
// 不用类型声明
MathOperation subtraction = (a, b) -> a - b;
- オプションのパラメーター括弧:パラメーターは括弧を定義する必要はありませんが、パラメーターまたは複数のパラメーターが括弧を定義する必要はありません。
// 不用括号
GreetingService greetService1 = message ->
System.out.println("Hello " + message);
// 用括号
GreetingService greetService2 = (message) ->
System.out.println("Hello " + message);
- オプションの中括弧:本文にステートメントが含まれている場合、中括弧は必要ありません。
// 多条语句不可以省略大括号
MathOperation multiplication = (int a, int b) -> {
int num = a+1;
num = a + b;
return a * b + num;
};
// 单条语句可以省略大括号
MathOperation division = (int a, int b) -> a / b;
- オプションのreturnキーワード:本体に式からの戻り値が1つしかない場合、コンパイラーは自動的に値を返します。中括弧は、式が値を返すことを指定する必要があります。
// 多条语句的Lambda表达式如果有返回值,需要使用return
MathOperation multiplication = (int a, int b) -> {
int num = a+1;
num = a + b;
return a * b + num;
};
// 单条语句可以省略return
MathOperation division = (int a, int b) -> a / b;
第4に、ラムダ式の使用範囲
ラムダ式は、匿名クラスの作成を単純化するために使用されるだけでなく、さらに多くの用途があります。
1.変数に値を割り当てます
上記では、Lambda式の使用法は、変数値を割り当てる書き込み方法です。これにより、匿名内部クラス割り当てのコードセグメントが簡素化され、読み取り効率が向上します。
MathOperation subtraction = (a, b) -> a - b;
2.返品の結果として
interface MathOperation {
int operation(int a, int b);
}
MathOperation getOperation(int a, int b){
return (a1, b1) -> a+b;
}
3、配列要素として
MathOperation math[] = {
(a,b) -> a+b,
(a,b) -> a-b,
(a,b) -> a*b
};
4.通常のメソッドまたはコンストラクターのパラメーターとして
public static void main(String args[]){
Java8Tester java8Tester = new Java8Tester();
java8Tester.operate(1,2,((a, b) -> a*b));
}
private int operate(int a, int b, MathOperation mathOperation){
return mathOperation.operation(a, b);
}
interface MathOperation {
int operation(int a, int b);
}
5、ラムダ式のスコープ
ラムダ式の式本体内では、式本体外の変数にアクセスできますが、他の変数は変更できません。
6、ラムダ式リファレンスライティング
Lambdaを学習するとき、次のコードなどの奇妙な書き方を見つけることもあります。
// 方法引用写法
GreetingService greetingService = System.out::println;
greetingService.sayMessage("hello world");
メソッド参照と呼ばれる、これまでにないシンボル::があります。
明らかに、メソッド参照の使用は、通常のラムダ式よりも少し簡潔です。
メソッドを呼び出すことで機能インターフェイスの実装が実現できる場合は、メソッド参照を使用できます。
public class Java8Tester {
public static void main(String args[]){
// 静态方法引用--通过类名调用
GreetingService greetingService = Test::MyNameStatic;
greetingService.sayMessage("hello");
Test t = new Test();
//实例方法引用--通过实例调用
GreetingService greetingService2 = t::myName;
// 构造方法方法引用--无参数
Supplier<Test> supplier = Test::new;
System.out.println(supplier.get());
}
interface GreetingService {
void sayMessage(String message);
}
}
class Test {
// 静态方法
public static void MyNameStatic(String name) {
System.out.println(name);
}
// 实例方法
public void myName(String name) {
System.out.println(name);
}
// 无参构造方法
public Test() {
}
}
7.ラムダ式の長所と短所
アドバンテージ:
-
コードの行数が少ない-ラムダ式の最大の利点の1つは、コードの量が減ることです。ご存知のように、ラムダ式は関数型インターフェースでのみ使用できます。たとえば、Runnableはインターフェースであるため、ラムダ式を簡単に適用できます。
-
順次実行と並列実行は、メソッドのパラメーターとして動作を渡すことでサポートされます。Java8でStream APIを使用すると、関数がコレクションメソッドに渡されます。現在、コレクションの責任は、要素を順次または並列に処理することです。
-
効率の向上-StreamAPIとラムダ式を使用することで、コレクションのバッチ操作の場合に効率(並列実行)を向上させることができます。また、ラムダ式は、外部反復ではなく、コレクションの内部反復を実現するのに役立ちます。
欠点
- 運用効率-並列コンピューティングがなければ、多くの場合、コンピューティング速度は従来のforループよりも速くはありません。(並列コンピューティングでは、効率の利点を示すためにウォームアップが必要になる場合があります)
- デバッグが難しい-Lambda式はブレークポイントになりにくく、デバッグに適していません。
- 理解するのは簡単ではありません-他のプログラマーがラムダ式を学習していない場合、コードは他の言語のプログラマーが理解するのは簡単ではありません(ラムダ式を学習した理由は、書かれたラムダ式コードを理解できないためです私の同僚による)