Java 8新機能:Lambda式の役割ドメイン(Lambda式補完版)
Lambda式の役割ドメイン
文|莫若吻
Lambda式では、外部の役割ドメインと古いバージョンの匿名オブジェクトにアクセスする方法が似ています.finalがマークされた外層ローカル変数、またはインスタンスのフィールド、および静的変数に直接アクセスできます.
Lambda式はスーパークラス(supertype)から変数名を継承せず、新しい役割ドメインも導入しません.Lambda式は文法的役割ドメインに基づいています.つまり、lambda式関数体の変数とその外部環境の変数は同じ意味を持っています.(lambda式の形式パラメータも含む).また、thisキーワードとその参照は、Lambda式の内部と外部でも同じ意味を持つ.
Lambda式全文アドレス:http://blog.csdn.net/sun_promise/article/details/51121205
1.ローカル変数へのアクセス
1)lambda式で外層のローカル変数に直接アクセスできる
eg:
ただし、匿名オブジェクトとは異なり、lambda式のローカル変数(eg:num)はfinalとして宣言する必要はありません.
eg:
ただし、ここでのローカル変数(eg:num)は、後続のコードによって変更されてはならない(すなわち、finalの意味を隠す)
eg:次のコードはコンパイルできません
Note:Lambda式でローカル変数を変更しようとすることは許されません.
2)Lambda式で参照される変数の値は変更できません.
3)Lambda式では、ローカル変数と同じ名前のパラメータまたはローカル変数を宣言することはできません.
eg:
2.アクセスオブジェクトフィールドと静的変数
ローカル変数とは異なり、Lambda内部のインスタンスのフィールド(すなわち、メンバー変数)および静的変数は、読み取り可能で書き込み可能である.
eg:
3.インタフェースにアクセスできないデフォルトの方法
Lambda式ではデフォルトメソッドにアクセスできません.
4.Lambda式のthis
Lambda式でthisを使用すると、Lambda式を作成する方法のthisパラメータが参照されます.
eg:
結果を表示:Lambda
5.Lambda式の役割ドメインを総合的に理解する
(注:上記の3つの内容が理解されている場合は、次の例や分析をよく見る必要はありません.)
eg:
分析:
Lambda式の変数countとtextは、Lambda式では定義されず、メソッドのパラメータです.Lambda式はrepeatMessage()が返されてから実行される可能性がありますが、パラメータ変数は消えています.textとcount変数を保持したらどうなりますか?
上記の状況をよりよく理解するためには,Lambda式をより深く理解する必要がある.
lambda式には、次の3つのセクションがあります.のコードです. パラメータ. 自由変数の値.ここで、「自由」とは、パラメータではなく、コードに定義されていない変数を指す.
例では、lambda式には2つの自由変数、text、countがあります.データ構造は、Lambda式がこの2つの変数の値を格納する必要があることを示します.すなわち、「Hello world」
」と20.これらの値はLambda式によって取得されたと理解できます(これは技術的な実装の詳細です.eg:lambda式を1つの方法しか含まれていないオブジェクトに変換することができ、自由変数の値がオブジェクトのインスタンス変数にコピーされます).
Note:自由変数を含むコードブロックは「クローズドパッケージ(closure)」と呼ばれます.Javaではlambda式がクローズドパッケージです.実際、内部クラスはずっとクローズドパッケージです.Java 8ではクローズドパッケージにもっと魅力的な構文が付与されています.
Lambda式は、閉じた役割ドメインの変数値をキャプチャします.Javaでは、取得された値が良好に定義されていることを確認するために、重要な制約を遵守する必要があります.Lambda式では、参照される変数の値は変更できません.
eg:次の式は合法的ではありません.
この制約をするには理由がある.Lambda式の変数を変更するのはスレッドが安全ではありません.一連の同時タスクがあると仮定すると、各スレッドは共有カウンタを更新します.
コンパイラがすべての同時アクセスエラーをキャプチャすることを期待しないでください.可変制約はローカル変数にのみ作用し、matchesがインスタンス変数または閉じたクラスの静的変数である場合、結果が同じように定義されていなくてもエラーは報告されません.同様に、共有オブジェクトを変更することも完全に合法的であり、それが適切でなくても.
Note:matchesは「有効final」です(有効なfinal変数が初期化されると、新しい値の変数は与えられません).我々の例では、matchesは常に同じArrayListオブジェクトを参照していますが、このオブジェクトは可変であるため、スレッドは安全ではありません.複数のスレッドがaddメソッドを同時に呼び出すと、結果は予測できません.Lambda式のメソッドボディとネストされたコードブロック同じ役割ドメインを持っています.したがって、同じ名前の競合およびシールドルールも適用されます.Lambda式では、ローカル変数と同じ名前のパラメータまたはローカル変数を宣言することはできません.
1つの方法では、同じ名前のローカル変数を2つ持つことはできません.そのため、lambda式にこのような変数を導入することはできません.
Lambda式でthisキーを使用すると、Lambda式を作成する方法のthisパラメータを参照します.
eg:
式this.toString()は、RunnableインスタンスのtoString()メソッドではなく、ApplicationオブジェクトのtoString()メソッドを呼び出します.Lambda式でthisを使うのは、他の場所でthisを使うのと変わらない.Lambda式の役割ドメインはdoWork()メソッドにネストされ,thisがメソッドのどこにあるかにかかわらず,その意味は同じである.
文|莫若吻
Lambda式では、外部の役割ドメインと古いバージョンの匿名オブジェクトにアクセスする方法が似ています.finalがマークされた外層ローカル変数、またはインスタンスのフィールド、および静的変数に直接アクセスできます.
Lambda式はスーパークラス(supertype)から変数名を継承せず、新しい役割ドメインも導入しません.Lambda式は文法的役割ドメインに基づいています.つまり、lambda式関数体の変数とその外部環境の変数は同じ意味を持っています.(lambda式の形式パラメータも含む).また、thisキーワードとその参照は、Lambda式の内部と外部でも同じ意味を持つ.
Lambda式全文アドレス:http://blog.csdn.net/sun_promise/article/details/51121205
1.ローカル変数へのアクセス
1)lambda式で外層のローカル変数に直接アクセスできる
eg:
final int num = 1;
Converter s =
(param) -> String.valueOf(param + num);
s.convert(2); // 3
ただし、匿名オブジェクトとは異なり、lambda式のローカル変数(eg:num)はfinalとして宣言する必要はありません.
eg:
int num = 1;
Converter s =
(param) -> String.valueOf(param + num);
stringConverter.convert(2); // 3
ただし、ここでのローカル変数(eg:num)は、後続のコードによって変更されてはならない(すなわち、finalの意味を隠す)
eg:次のコードはコンパイルできません
int num = 1;
Converter s =
(param) -> String.valueOf(param + num);
num = 5;
Note:Lambda式でローカル変数を変更しようとすることは許されません.
2)Lambda式で参照される変数の値は変更できません.
public void repeat(String string, int count) {
Runnable runnable = () -> {
for (int i = 0; i < count; i++) {
string = string + "a";//
System.out.println(this.toString());
}
};
new Thread(runnable).start();
}
3)Lambda式では、ローカル変数と同じ名前のパラメータまたはローカル変数を宣言することはできません.
eg:
String first = "";
Comparator comparator = (first, second) -> Integer.compare(first.length(),//
second.length());
2.アクセスオブジェクトフィールドと静的変数
ローカル変数とは異なり、Lambda内部のインスタンスのフィールド(すなわち、メンバー変数)および静的変数は、読み取り可能で書き込み可能である.
eg:
class LambdaDemo {
static int myStaticNum;
int myNum;
void testScopes() {
Converter s1 = (param) -> {
myNum = 33;
return String.valueOf(param);
};
Converter s2 = (param) -> {
myStaticNum = 87;
return String.valueOf(param);
};
}
}
3.インタフェースにアクセスできないデフォルトの方法
Lambda式ではデフォルトメソッドにアクセスできません.
4.Lambda式のthis
Lambda式でthisを使用すると、Lambda式を作成する方法のthisパラメータが参照されます.
eg:
public class Test2 {
public static void main(String[] args) {
Test2 test = new Test2();
test.method();
}
@Override
public String toString() {
return "Lambda";
}
public void method() {
Runnable runnable = () -> {
System.out.println(this.toString());
};
new Thread(runnable).start();
}
}
結果を表示:Lambda
5.Lambda式の役割ドメインを総合的に理解する
(注:上記の3つの内容が理解されている場合は、次の例や分析をよく見る必要はありません.)
eg:
public class Test {
public static void main(String[] args) {
repeatMessage("Hello world", 20);
}
public static void repeatMessage(String text,int count){
Runnable r = () -> {
for(int i = 0; i < count; i++){
System.out.println(text);
Thread.yield();
}
};
new Thread(r).start();
}
}
分析:
Lambda式の変数countとtextは、Lambda式では定義されず、メソッドのパラメータです.Lambda式はrepeatMessage()が返されてから実行される可能性がありますが、パラメータ変数は消えています.textとcount変数を保持したらどうなりますか?
上記の状況をよりよく理解するためには,Lambda式をより深く理解する必要がある.
lambda式には、次の3つのセクションがあります.
例では、lambda式には2つの自由変数、text、countがあります.データ構造は、Lambda式がこの2つの変数の値を格納する必要があることを示します.すなわち、「Hello world」
」と20.これらの値はLambda式によって取得されたと理解できます(これは技術的な実装の詳細です.eg:lambda式を1つの方法しか含まれていないオブジェクトに変換することができ、自由変数の値がオブジェクトのインスタンス変数にコピーされます).
Note:自由変数を含むコードブロックは「クローズドパッケージ(closure)」と呼ばれます.Javaではlambda式がクローズドパッケージです.実際、内部クラスはずっとクローズドパッケージです.Java 8ではクローズドパッケージにもっと魅力的な構文が付与されています.
Lambda式は、閉じた役割ドメインの変数値をキャプチャします.Javaでは、取得された値が良好に定義されていることを確認するために、重要な制約を遵守する必要があります.Lambda式では、参照される変数の値は変更できません.
eg:次の式は合法的ではありません.
public static void repeatMessage(String text,int count){
Runnable r = () -> {
while(count > 0){
count--; // ,
System.out.println(text);
Thread.yield();
}
};
new Thread(r).start();
}
この制約をするには理由がある.Lambda式の変数を変更するのはスレッドが安全ではありません.一連の同時タスクがあると仮定すると、各スレッドは共有カウンタを更新します.
int matches = 0;
for(Path p : files)
new Thread(() -> {if(p ) matches++;}).start(); // matches
コンパイラがすべての同時アクセスエラーをキャプチャすることを期待しないでください.可変制約はローカル変数にのみ作用し、matchesがインスタンス変数または閉じたクラスの静的変数である場合、結果が同じように定義されていなくてもエラーは報告されません.同様に、共有オブジェクトを変更することも完全に合法的であり、それが適切でなくても.
List matches = new ArrayList<>();
for(Path p: files)
// matches ,
new Thread(() -> {if(p ) matches.add(p);}).start();
Note:matchesは「有効final」です(有効なfinal変数が初期化されると、新しい値の変数は与えられません).我々の例では、matchesは常に同じArrayListオブジェクトを参照していますが、このオブジェクトは可変であるため、スレッドは安全ではありません.複数のスレッドがaddメソッドを同時に呼び出すと、結果は予測できません.Lambda式のメソッドボディとネストされたコードブロック同じ役割ドメインを持っています.したがって、同じ名前の競合およびシールドルールも適用されます.Lambda式では、ローカル変数と同じ名前のパラメータまたはローカル変数を宣言することはできません.
Path first = Paths.get("/usr/bin");
Comparator comp = (first,second) ->
Integer.compare(first.length(),second.length());
// , first
1つの方法では、同じ名前のローカル変数を2つ持つことはできません.そのため、lambda式にこのような変数を導入することはできません.
Lambda式でthisキーを使用すると、Lambda式を作成する方法のthisパラメータを参照します.
eg:
public class Application{
public void doWork(){
Runnable runner = () -> {....;System.out.println(this.toString());......};
}
}
式this.toString()は、RunnableインスタンスのtoString()メソッドではなく、ApplicationオブジェクトのtoString()メソッドを呼び出します.Lambda式でthisを使うのは、他の場所でthisを使うのと変わらない.Lambda式の役割ドメインはdoWork()メソッドにネストされ,thisがメソッドのどこにあるかにかかわらず,その意味は同じである.