ラムダ式
関数型プログラミングのアイデアの概要
数学では、関数は、ある計算プログラムの出力の入力を持つことである「何かを得るために何かをするの。」これとは対照的に、「オブジェクトは、物事の形で行われなければならない」とオブジェクト指向構文の機能の複雑さのアイデアを無視しようとする上で、オブジェクト指向強調しすぎる、どのような形で行うのではなく、何をすべきかを強調する。
オブジェクト指向の考え方:
- 物事を成し遂げるために、オブジェクトのメソッドを呼び出して、この問題を解決するために、ターゲットを探して、一つのことを行います。
関数型プログラミングのアイデア:
- 限り行う結果、に着くと、どのように行うには、重要なのは結果であり、プロセスに注意を払っていない重要ではありません。
2.冗長コード
[実施例1]従来の文言
あなたがタスクを完了するためにスレッドを開始する必要がある場合は、タスクは通常、コンテンツjava.lang.Runnableのインターフェイスで定義されており、スレッドを開始したjava.lang.Threadクラスを使用します。コードは以下の通りであります:
public class DemoRunnable {
public static void main(String[] args) {
// 匿名内部类
Runnable task = new Runnable() {
@Override
public void run() { // 覆盖重写抽象方法
System.out.println("多线程任务执行!");
}
};
new Thread(task).start(); // 启动线程
}
}
で、「すべてのものがオブジェクトである、」このアプローチの考え方は理解できる:最初のタスクの内容を指定するには、匿名の内部クラスオブジェクト、Runnableインタフェースを作成し、起動するスレッドに引き渡さ。
〔実施例1〕解析コード
Runnableを匿名内部クラスを使用するためには、いくつかの点を分析することができます:
- スレッドクラスは、メソッドがタスクの内容を指定するために使用される抽象コアスレッドを実行されるパラメータとして、Runnableインタフェースを必要。
- 体を指定して実行するには、我々は、Runnableインタフェースクラスを達成するための必要性を。
- RunnableImpl実装クラスを定義する手間を省くために、我々はしなければならなかった匿名内部クラスを使用します。
- これは、メソッドの戻り値は、メソッドを実行する必要があり、抽象、そのメソッド名、メソッドのパラメータを上書きする必要が再び書き込み、および表示することができません。
- 実際には、鍵が唯一の方法体であると思われます。
[実施例2]従来の文言
あなたは通常、インターフェースjjava.util.Comparatorソート方法によって定義されたカスタムソートTreeSetのコレクションを、必要とし、TreeSetの(コンパレータ<?スーパーE>コンパレータ)を使用する場合、このコンストラクタが呼び出されます。コードは以下の通りであります:
public class DemoComparator {
public static void main(String[] args) {
// 匿名内部类
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) { // 覆盖重写抽象方法
return Integer.compare(o1, o2);
}
};
TreeSet<Integer> set = new TreeSet<>(comparator);
}
}
[実施例2]解析コード
匿名内部クラスの場合は、コンパレータを使用して、いくつかのポイントを分析することができます。
- TreeSetのコアが指定されたソートを比較するための抽象メソッドであることを特徴パラメータとして構成された比較器を必要とします。
- 指定されたメソッド本体を比較するために、我々はしているインタフェースの実装クラスのコンパレータを必要と。
- comparatorImpl実装クラスのトラブル定義を保存するために、我々はしなければならなかった匿名内部クラスを使用します。
- メソッドの戻り値を比較する抽象メソッド、メソッド名、メソッドのパラメータ、上書きでなければなりませんしなければなら再び書き込み、および表示することができません。
- 実際には、唯一のパラメータおよび方法体が鍵となります。
3.変換プログラミングのアイデア
むしろ行う方法よりも、何をします
私たちは本当に匿名の内部クラスのオブジェクトを作成したいですか?いいえ。私達はちょうどそれを行うとする必要はありオブジェクトを作成します。パスコードが知られている生体Threadクラスを実行するために:私たちは本当にされて行うことを願っています。
コードの一部を渡す -これが私たちの真の目的です。そして、唯一のオブジェクト指向構文の手段により制限されたオブジェクトを作成し、取らなければなりませんでした。まあ、ない簡単な方法はありませんか?私たちは、「操作方法」のエッセンスの「何」に戻るから焦点を当てた場合は、限り、あなたは自分の目標を達成しやすくなり見つかりますよう、プロセスおよびフォームは本当に重要ではありません。
リビングの例
私たちは北京から上海に必要がある場合、あなたは高速鉄道、車、サイクリングやウォーキングを選択することができます。私たちの真の目的は、どのようにフォームを取得することが重要ではない上海、上海、に到達することですので、我々は、高鉄より良い方法はありません模索してきた - 飛ぶが。
そして今、この航空機(あるいは宇宙船)が生まれてきた:2014年3月Oracleが追加、8(JDK 1.8)でJavaをリリースラムダ式に我々は新しい世界への扉を開いたとして、ヘビー級の新機能を。
4.より良い経験ラムダ文言
Javaの8の新しい構文を使用すると、匿名内部クラスの上記の例は、単純なラムダ式を書くのと同等に到達することができます:
public class DemoLambdaRunnable {
public static void main(String[] args) {
new Thread(() -> System.out.println("多线程任务执行!")).start(); // 启动线程
}
}
public class DemoLambdaComparator {
public static void main(String[] args) {
TreeSet<Integer> set = new TreeSet<>((x, y) -> Integer.compare(x, y));
}
}
そして、このコードの結果の実装は、コンパイラレベル1.8以上で、ちょうどまったく同じです。
そこに、「インタフェースオブジェクトを作成する必要がありました」束縛されなくなり、もはや「上書き抽象メソッド」の負担を持って、簡単なことではありません!
5.匿名内部クラスを想起
ラムダは、オブジェクト指向を倒すためにどのようにでしょうか?上記の例では、コアコードは、以下に示されています。
() -> System.out.println("多线程任务执行!");
(x, y) -> Integer.compare(x, y);
ラムダの意味を理解するために、我々は伝統的なコードから開始する必要があります。
その実装クラス
スレッドを起動するには、我々は、Threadクラスのオブジェクトを作成し、メソッドを開始呼び出す必要があります。スレッドの実行の内容を特定するためには、Threadクラスのコンストラクタを呼び出します。
- 公共のスレッド(Runnableを対象)
RunnableImplのクラスインターフェース定義を実装することができる、Runnableインタフェースを実装するオブジェクトを得るために:
public class RunnableImpl implements Runnable {
@Override
public void run() {
System.out.println("多线程任务执行!");
}
}
そして、Threadクラスのコンストラクタのパラメータとして実装クラスのオブジェクトを作成します。
public class Demo03ThreadInitParam {
public static void main(String[] args) {
Runnable task = new RunnableImpl();
new Thread(task).start();
}
}
[実施例2]ソートさTreeSetの同様に、本明細書に記載されていません。
匿名内部クラスの使用
ただ、Runnableインタフェースを達成するために、このRunnableImplクラスが存在し、唯一の時間のみを使用するので、匿名の内部クラスの構文を使用すると、別のクラスの定義を省略して、匿名内部クラスという。
public class Demo04ThreadNameless {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("多线程任务执行!");
}
}).start();
}
}
匿名内部クラスの利点と欠点
一方で、匿名内部クラスがために私たちを助けることができる実装クラスを定義省略し、一方、匿名内部クラスの構文- 実際には複雑すぎます!
意味解析
コードの意味を慎重に分析、、Runnableインタフェースのrunメソッドの定義のみ:
- パブリック抽象ボイドラン();
それは、物事を行うためのプログラム(実際には、機能)を開発するために、次のとおりです。
- 引数なしません:任意の条件なしのプログラムを実施します。
- なし戻り値:このスキームは、任意の結果を生成しません。
- コードブロック(方法):プログラムの特定のステップ。
同じセマンティックは、よりシンプルに、ラムダ構文に反映しました:
() -> System.out.println("多线程任务执行!")
- 括弧すなわち一対のフロント
run
任意の条件を必要としない方法のパラメータ(なし)。 - 中間の矢印は、背後にあるコードの前に渡されるパラメータを表します。
- すなわち、ビジネス・ロジック・コードの出力文の背後にあります。
6.ラムダ標準フォーマット
ラムダは、オブジェクト指向のルールを省略し、そしてフォーマットが構成されて三つの部分:
- 一部のパラメータ
- 矢印
- コードの一部
ラムダ式は、標準のフォーマットは以下のとおりです。
(参数类型 参数名称) -> { 代码语句 }
形式説明:
- 一貫した括弧内の構文常法パラメータリスト:空のパラメータ、複数のパラメータはカンマで区切られています。
- - >アクションを指しているのに代わって、導入された新しい構文です。
- 従来の方法で構文体が一貫した括弧を必要とします。
7.ラムダ省略形式
省略することができる導くことができます
ラムダではなく、「行う方法」よりもその「何か」を強調し、両方がそのコンテキストを推定することができるように情報に応じて、省略することができます。
楕円形のルール
標準フォーマットラムダに基づき、言葉遣いのために使用されるルールを省略:
- 括弧内の型パラメータが省略されてもよいです。
- 括弧場合と一つのパラメータのみ、括弧を省略することができます。
- 括弧場合のみ1文が、関係なく、戻り値があるかどうかの、あなたは中括弧を省略することができ、キーワードやセミコロンを返します。
8.ラムダの利用を前提
ラムダ構文には、オブジェクト指向の複雑な制約がない、非常に簡単です。しかし、使用している場合、特別な注意を必要とするいくつかの問題があります。
(1)インターフェース、および必要有していなければならないラムダを使用してインターフェースと一つだけ抽象メソッド。かどうかはJDKは抽象インタフェース・メソッドとする場合にのみ、ラムダを使用することができますがある場合にのみ、コンパレータインターフェイスまたはカスタムインタフェースRunnableを構築しました。
(2)ラムダをしなければならない使用してコンテキストを推論します。この方法は、ローカル変数または引数タイプラムダはラムダインタフェースの一例として使用するインタフェースタイプを対応する必要があります。
注意:1つのインターフェースのみと抽象メソッドがあり、と呼ばれる「関数インタフェース。」
9.練習
(1)なしなし戻りパラメータ
タイトル
クックは、指定されたインタフェースを調理し、makeFoodはパラメータを唯一の抽象メソッドを含まず、値を返しません。次のように:
public interface Cook {
void makeFood();
}
次のコードでは、ラムダ使う標準形式はプリントアウトし、invokeCookメソッドを呼び出して単語を「それを食べるために!」:
public class DemoInvokeCook {
public static void main(String[] args) {
// 请在此使用Lambda【标准格式】调用invokeCook方法
}
private static void invokeCook(Cook cook) {
cook.makeFood();
}
}
答え
public static void main(String[] args) {
invokeCook(() -> {
System.out.println("吃饭啦!");
});
}
注意:括弧はクックインタフェースmakeFood抽象的なアプローチをパラメータ表し方法はmakeFood本体に代わってブレース、空です。
(2)参照を返します
タイトル
二つの数及びINT値を加算することによって得ることができる抽象メソッドを含む計算機の計算機インターフェースCALC与えられます:
public interface Calculator {
int calc(int a, int b);
}
以下のコードでは、ラムダ使用する標準フォーマット 120および130の完了を加算することにより算出される、invokeCalcメソッドを呼び出します。
public class Demo08InvokeCalc {
public static void main(String[] args) {
// 请在此使用Lambda【标准格式】调用invokeCalc方法来计算120+130的结果
}
private static void invokeCalc(int a, int b, Calculator calculator) {
int result = calculator.calc(a, b);
System.out.println("结果是:" + result);
}
}
答え
public static void main(String[] args) {
invokeCalc(120, 130, (int a, int b) -> {
return a + b;
});
}
注:括弧は電卓インターフェイスパラメータカルク抽象メソッドを表し、メソッド本体は、カルクに代わってブレース。