なぜラムダ式を使用するのか
いくつかの例を見てみましょう。
最初の例は、通常、次のように実装する別のスレッドでタスクを実行することです。
クラスワーカーはrunnable {public void run(){for(int i = 0; i <100; i ++)dowork(); } ...} worker w = new Worker();新しいスレッド(w).start();2番目の例は、カスタム文字列比較方法(文字列の長さによる)です。これは一般的に行われます。
クラスの長さのコンパレーターは、Comparator <String> {public int(String first、String second){return integer.compare(first.length()、second.length()); }} arrays.sort(strings、new lengthComparator());3番目の例では、Javafxで、ボタンにコールバックを追加します。
button.setOnaction(new EventHandler <ActionEvent>(){public void handle(ActionEvent event){system.out.println( "クリックしてくれてありがとう!");}});これらの例には、共通点が1つあります。つまり、最初にコードのブロックを定義し、オブジェクトまたはメソッドに渡してから実行することです。 Lambda式の前に、Javaはオブジェクト指向であるため、Javaはコードブロックの直接通過を許可していないため、オブジェクトを渡すにはオブジェクトを渡す必要があります。
Lambda Expression構文
上記の2番目の例のLengthComparatorは、ラムダ式として表されます。
(string first、string second) - > integer.compare(first.length()、second.length());
- >以前はパラメーターリストで、次に式のステートメント本文が続きます。
式ステートメントの本文が複数の行の場合、ステートメントの本文は{}で書かれています。
(string first、string second) - > {if(first.length()> second.length()){return 1; } else if(first.length()== second.length()){return 0; } else {return -1; }};パラメーターがない場合は、()を持ち込む必要があります。たとえば、上記の最初の例は、次のように表現できます。
() - > {for(int i = 0; i <1000; i ++){dowork(); }}パラメーターのタイプをコンテキストから自動的に推測できる場合、次のことを省略できます。
Comparator <String> comp =(first、second)//同じ(string first、string second) - > integer.compare(first.length()、second.length());
パラメーターが1つだけで、タイプを自動的に推測できる場合、brackets()も省略できます。
//(event) - >または(ActionEvent event) - > eventHandler <ActionEvent>リスナー= event-> system.out.println( "クリックしてくれてありがとう!");
ラムダ式の戻り値のタイプは自動的に推測されるため、指定する必要はありません。ラムダの表現では、一部の条件付きブランチには戻り値がありますが、他のブランチには戻り値がありません。これは許可されていません。
(x) - > {if(x> = 0){return 1; }}さらに、発現ラムダと声明ラムダの違いは、式ラムダがリターンキーワードを書く必要がないということです。 Javaランタイムは式の結果を返品値として返しますが、ステートメントラムダは{}で書かれた式であり、リターンキーワードを使用する必要があります。
//式lambdacomparator <string> comp1 =(first、second) - > integer.compare(first.length()、second.length()); // statement lambdacomparator <string> comp2 =(first、second) - > {return integer.compare(first.length()、second.length();};};機能インターフェイス
インターフェイスに抽象的なメソッドが1つしかない場合、それは呼び出されます
実行可能、コンパレータなどの機能的インターフェイス。
機能的なインターフェイスオブジェクトが必要な場所では、ラムダ式を使用できます。
arrays.sort(words、(first、second) - > integer.compare(first.length()、second.length()));
ここで、sort()の2番目のパラメーターにはコンパレータオブジェクトが必要で、コンパレータは
機能的なインターフェイスでは、ラムダ式を直接渡すことができます。オブジェクトの比較()メソッドを呼び出すとき、それはラムダ式でステートメント本体を実行することです。
Lambda式のステートメントが例外をスローする場合、機能インターフェイスの対応する抽象的なメソッドは例外をスローする必要があります。そうしないと、ラムダ式で例外を明示的にキャッチする必要があります。
runnable r =() - > {system.out.println( "-------"); try {thread.sleep(10); } catch(arternedexception e){// catch exception}}; callable <string> c =() - > {system.out.println( "----------"); thread.sleep(10);戻る "";};メソッド参照
ラムダ式のパラメーターがメソッドのパラメーターとして渡され、その実行効果が同じである場合、ラムダ式はメソッド参照を使用して表現でき、次の2つの方法は同等です。
(x) - > system.out.println(x)system.out :: println
その中で、System.out :: printlnはメソッドリファレンスと呼ばれます。
メソッドリファレンスには主に3つの形式があります。
最初の2つの方法では、対応するラムダ式パラメーターとメソッドパラメーターは次のように同じです。
System.out :: println(x) - > System.out.println(x)Math :: pow(x、y) - > math.pow(x、y)
3番目の方法では、対応するLambda式のステートメント本体では、最初のパラメーターがオブジェクトとして使用され、メソッドが呼び出され、その他のパラメーターは次のようなメソッドパラメーターとして使用されます。
String :: ComparetoignoreCase(S1、S2) - > S1.comPareToignOreCase(S2)1.5コンストラクターリファレンス
コンストラクターの参照はメソッドリファレンスに似ていますが、特別な方法です:新しい方法。特定のコンストラクターは、次のようなコンテキスト環境によって決定されます。
List <String> Labels = ...; Stream <button> stream = labels.stream()。マップ(ボタン:: new);
ボタン:: newは(x) - > button(x)に相当するため、IS:button(x)と呼ばれるコンストラクターは;
単一のオブジェクトを作成することに加えて、次の2つの同等物などのオブジェクトの配列を作成することもできます。
int [] :: new(x) - > new int [x]
可変スコープ
LAMBD式は、次のような現在の範囲で利用可能な変数をキャプチャします。
public void RepeatMessage(string text、int count){runnable r =() - > {for(int i = 0; i <count; i ++){system.out.println(text); thread.yield(); }};新しいスレッド(r).start();}しかし、これらの変数は不変でなければなりません、なぜですか?次の例を参照してください。
int matches = 0; for(path p:files)new thread(() - > {if(pがあるプロパティ)一致++;})。start(); //一致を変異させる違法可変変数はラムダ式ではスレッドセーフではないため、これは内部クラスの要件と一致しており、外部から定義された最終変数のみが内部クラスで参照できます。
ラムダ式の範囲はネストされたコードブロックの範囲と同じであるため、ラム式のパラメーター名または変数名は、次のようなローカル変数と矛盾することはできません。
パスfirst = paths.get( "/usr/bin"); comparator <string> comp =(first、second) - > integer.compare(first.length()、second.length()); //エラー:最初に既に定義されている変数
この変数がラムダ式で参照されている場合、参照は次のようなラムダ式を作成するメソッドのこの変数です。
public class application(){public void dowork(){runnable runner =() - > {...; system.out.println(this.toString()); ...}; }}ここでthis.toString()はアプリケーションオブジェクトのtoString()を呼び出しますが、実行できません
オブジェクト。
デフォルトメソッド
インターフェイスには抽象的なメソッドしかありません。既存のインターフェイスに新しいメソッドが追加された場合、インターフェイスのすべての実装クラスがこのメソッドを実装する必要があります。
Java 8は、デフォルトメソッドの概念を導入し、デフォルトメソッドをインターフェイスに追加しますが、これは既存のインターフェイスルールを破壊しません。インターフェイス実装クラスは、次のようなデフォルトメソッドをオーバーライドまたは直接継承することを選択できます。
インターフェイス担当者{long getId();デフォルトの文字列getName(){return "John Q. public"; }}Javaは複数の継承を許可します。クラスの親クラスで定義されている方法がインターフェイスで定義されているデフォルトのメソッドとまったく同じ場合、またはクラスの2つのインターフェイスがまったく同じである場合、この競合に対処する方法、この競合に対処する方法処理ルールは次のとおりです。
メソッドが親クラスとインターフェイスとの間に矛盾する場合:親クラスのメソッドが勝ち、インターフェイス内のメソッドは無視されます。
2つのインターフェイスのデフォルトメソッドが競合する場合、競合を解決する方法をオーバーライドする必要があります。
静的メソッド
Java 8の前に、インターフェイスで静的変数のみを定義できます。 Java 8から始めて、静的メソッドをインターフェイスに追加できます。
Comparator Interfaceは、次のような比較の一連の静的方法を追加しました。
public static <t> comparator <t> comparingint(tointfunction <?super t> keyextractor){objects.requirenonnull(keyextractor); return(Comparator <T>&Serializable)(C1、C2) - > integer.compare(keyextractor.applyasint(c1)、keyextractor.applyasint(c2));}この静的方法を使用して、次の2つの方法も同等です。
1。
arrays.sort(都市、(最初、2番目) - > integer.compare(first.length()、second.length()));
2。
arrays.sort(Cities、comparator.comparingint(string :: length));
したがって、将来独自のインターフェイスを設計する場合、個別のツールクラス(コレクション/コレクションなど)を定義する必要はなくなりました。
インターフェイスで静的メソッドを使用するだけです。
匿名の内部クラス
Javaの世界では、匿名の内部クラスがアプリケーションで1回しか実行できない操作を実装できます。たとえば、Androidアプリケーションでは、ボタンクリックイベントが処理されます。クリックイベントを処理するために別のクラスを書く必要はありません。匿名の内側クラスでこれを行うことができます。
ボタンボタン=(ボタン)findViewByID(r.id.button1); button.setonclicklistener(new onclickListener(){@Override public void onclick(View View){toast.maketext(mainActivity.this、 "、"ボタンクリック "、toast.length_short).show();ラムダの例1。runnablelambdaいくつかの例を見てみましょう。これが実行可能の例です: public void runnabletest(){system.out.println( "=== runnabletest ==="); //匿名Runnable runnable r1 = new runnable(){@override public void run(){system.out.println( "hello world one!"); }}; // lambda runnable runnable r2 =() - > system.out.println( "Hello World Two!"); // 2つの実行機能r1.run()を実行します。 r2.run(); } public void runnabletest(){system.out.println( "=== runnabletest ==="); //匿名Runnable runnable r1 = new runnable(){@override public void run(){system.out.println( "hello world one!"); }}; // lambda runnable runnable r2 =() - > system.out.println( "Hello World Two!"); // 2つの実行機能r1.run()を実行します。 r2.run(); }実装も返品値も返されません。実行可能なラムダ式式コードブロックを使用して、5つの要素コードを1つのステートメントに簡素化します。 public class person {private string divensname;プライベート文字列姓;プライベートインクエイジ;私的性別の性別。プライベート文字列メール;プライベート文字列電話;プライベートストリングアドレス;} public class person {private string divensname;プライベート文字列姓;プライベートインクエイジ;私的性別の性別。プライベート文字列メール;プライベート文字列電話;プライベートストリングアドレス;}以下は、匿名の内側クラスとラムダ式を使用してコンパレータインターフェイスを実装する方法です。 public class comparetortest {public static void main(string [] args){list <person> personlist = person.createshortlist(); //インナークラスを使用してソートコレクションを実装します。Sort(PersonList、new Comparator <serson>(){public int Compare(person P1、person P2){return p1.getsurname()。比較(p2.getsurname());}}); system.out.println( "=== sorted asc surname ==="); for(person p:personlist){p.printname(); } // lambda式を使用した実装collections.sort(personlist、(person p1、person p2) - > p1.getsurname()。compareto(p2.getsurname())); for(person p:personlist){p.printname(); } // desc sunchential system.out.println( "=== sorted desc surname ==="); collections.sort(personlist、(p1、p2) - > p2.getsurname()。compareto(p1.getsurname())); for(person p:personlist){p.printname(); }}} public class comparetortest {public static void main(string [] args){list <person> personlist = person.createshortlist(); //インナークラスを使用してソートコレクションを実装します。Sort(PersonList、new Comparator <serson>(){public int Compare(person P1、person P2){return p1.getsurname()。比較(p2.getsurname());}}); system.out.println( "=== sorted asc surname ==="); for(person p:personlist){p.printname(); } // lambda式を使用した実装collections.sort(personlist、(person p1、person p2) - > p1.getsurname()。compareto(p2.getsurname())); for(person p:personlist){p.printname(); } // desc sunchential system.out.println( "=== sorted desc surname ==="); collections.sort(personlist、(p1、p2) - > p2.getsurname()。compareto(p1.getsurname())); for(person p:personlist){p.printname(); }}}匿名の内部クラスは、ラムダ式を通じて実装できることがわかります。最初のラムダ式は、パラメーターのタイプを人として定義することに注意してください。 2番目のラムダ式は、タイプ定義を省略します。 Lambda式は、タイプのノックダウンをサポートし、必要なタイプをコンテキストで推定できる場合、タイプ定義を省略できます。ここでは、一般的な定義を使用するコンパレータでラムダ式を使用するため、コンパイラはこれら2つのパラメーターを人として推測できます。