Java 8特性詳細(一)Lambda
13700 ワード
なぜlambda式を使うのか
関数インタフェースから
Functional Interface(関数インタフェース)を理解することはJava 8 lambda式を学ぶ上で重要なポイントです.
関数インタフェースの定義は簡単です.どのインタフェースも、唯一の抽象的な方法しか含まれていない場合は、関数インタフェースです.関数インタフェースの場合、lambda式でインタフェースのオブジェクトを作成できます.
コンパイラが関数インタフェースの要件を満たすインタフェース、すなわち抽象的な方法が1つしかないことを保証するのに役立ちます.Java 8では@FunctionalInterface注記が提供されています.簡単な例を挙げると、RunnableインタフェースはFIで、次はソースコードです.
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
@FunctionalInterface注釈を使用しても、必須ではありません.しかし、注釈を使用すると、コードがより明確に見えます.
Lambda式の文法糖
こうぶん糖
Javaのlambda式のフォーマット:パラメータ、矢印->、式.Lambda式の構文糖を実証するために,例としてComparatorを用いた.Java 8の前に匿名の内部クラスを利用して実現することができます.
public static List compareTest1(){
List wordList = Arrays.asList("lianggzone", "spring", "summer", "autumn", "winter");
wordList.sort(new Comparator() {
@Override
public int compare(String w1, String w2) {
return Integer.compare(w1.length(), w2.length());
}
});
return wordList;
}
Comparatorは関数インタフェースであり,Lambda式で実現できる.Lambda式は匿名の方法に似ていますが、カッコ内のパラメータリストとカッコ内のコードが->区切られています.
public static List compareTest2(){
List wordList = Arrays.asList("lianggzone", "spring", "summer", "autumn", "winter");
wordList.sort((String w1, String w2) -> {
return Integer.compare(w1.length(), w2.length());
});
return wordList;
}
lambda式のパラメータタイプが導出可能である場合、それらのタイプを省略することができる.
public static List compareTest3(){
List wordList = Arrays.asList("lianggzone", "spring", "summer", "autumn", "winter");
wordList.sort((w1, w2) -> {
return Integer.compare(w1.length(), w2.length());
});
return wordList;
}
lambda式のコードブロックがreturnの後に式が続くだけである場合、さらに簡略化することもできる.
public static List compareTest4(){
List wordList = Arrays.asList("lianggzone", "spring", "summer", "autumn", "winter");
wordList.sort((w1, w2) -> Integer.compare(w1.length(), w2.length()));
return wordList;
}
メソッドにパラメータが1つしか含まれていない場合、そのパラメータのタイプを導出することができ、カッコを省略することもできます.
public static List compareTest5(){
List wordList = Arrays.asList("lianggzone", "spring", "summer", "autumn", "winter");
wordList.forEach(word -> System.out.println(word));
return wordList;
}
別の独立したスレッドでいくつかの論理を実行する場合、通常、Runableインタフェースを実装するクラスのrunメソッドにコードが配置されます.
public static void runnableTest1(){
Executors.newSingleThreadExecutor().execute(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}
});
}
Lambda式にパラメータがない場合は、パラメータを含まない方法のように、空のカッコのペアを提供することができます.
public static void runnableTest2(){
Executors.newSingleThreadExecutor().execute(() -> {
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
});
}
注意点
メソッド参照
場合によっては、lambda式のコードは単純なメソッド呼び出しにすぎません.この場合、lambda式はメソッド参照にさらに簡略化されます.::オペレータは、メソッド名とオブジェクトまたはクラスの名前を区切ります.
オブジェクトおぶじぇくと:インスタンスオブジェクトれいとおぶじぇくと
Java 8の前に、リストの内容を印刷します.通常はそうします.
public static void print1(){
List wordList = Arrays.asList("lianggzone", "spring", "summer", "autumn", "winter");
wordList.forEach(new Consumer() {
@Override
public void accept(String word) {
System.out.println(word);
}
});
}
Consumerは関数インタフェースであるため,lambda式を改造した.
public static void print2(){
List wordList = Arrays.asList("lianggzone", "spring", "summer", "autumn", "winter");
wordList.forEach(word -> System.out.println(word));
}
メソッド参照に変更すると、式System.out::println、word->Systemに等しい.out.println(word).
public static void print3(){
List wordList = Arrays.asList("lianggzone", "spring", "summer", "autumn", "winter");
wordList.forEach(System.out::println);
}
クラス:インスタンスオブジェクト[くらす:れいとおぶじぇくと]
たとえば、大文字と小文字を区別せずに文字列をソートします.
public static String[] sort1(){
String[] words = new String[]{"lianggzone", "spring", "summer", "autumn", "winter"};
Arrays.sort(words, (x, y) -> x.compareToIgnoreCase(y));
return words;
}
メソッド参照に変更すると、式:String::compareToIgnoreCase(x,y)->x.compareToIgnoreCase(y)に等しく、第1のパラメータがメソッドを実行するオブジェクトになります.
public static String[] sort2(){
String[] words = new String[]{"lianggzone", "spring", "summer", "autumn", "winter"};
Arrays.sort(words, String::compareToIgnoreCase);
return words;
}
オブジェクト:静的メソッド静的メソッド
たとえば、コレクションをソートします.
public static List sortList1(){
List wordList = Arrays.asList(21, 53);
wordList.sort((w1, w2) -> Integer.compare(w1, w2));
return wordList;
}
メソッド参照に変更すると、式:Integer::compare、(w 1,w 2)->Integerに等しい.compare(w 1,w 2)では,第1パラメータが実行方法の対象となる.
public static List sortList2(){
List wordList = Arrays.asList(21, 53);
wordList.sort(Integer::compare);
return wordList;
}
コンストラクタリファレンス
// lambda
words.stream().map(word -> {
return new StringBuilder(word);
});
// constructor reference
words.stream().map(StringBuilder::new);
変数スコープ
Java 8以前は内部クラスはfinalのローカル変数にしかアクセスできなかったが,lambda式に適応するためにJava 8はこの制限を緩和し,変数が実際に可変でなければよい.
public static void effectivelyFinal(){
int a = 100;
Executors.newSingleThreadExecutor().execute(() -> {
System.out.println(a);
});
}
Lambda式では、参照される変数の値は変更できません.この制約を行うには、lambda式の変数がスレッドで安全ではないため、理由があります.
インタフェースの静的メソッド
Java 8から、インタフェースにも静的な方法があります.この文法があれば,インタフェースに関連するヘルプメソッドをインタフェースに直接定義することができる.
たとえばFunctionインタフェースは、ファクトリメソッドindentity()を定義します.値を割り当てるターゲットとしてlambda式またはメソッドの参照として使用できる機能インタフェースを示します.
T-関数入力のタイプR-関数の結果のタイプ
public interface Function {
static Function identity() {
return t -> t;
}
}
実際、Java 8では、多くのインタフェースに静的メソッドが追加されています.例えば、Java 8の使用例です.
public interface Path {
public static Path get(String first, String... more) {
return FileSystems.getDefault().getPath(first, more);
}
}
だから、大事なことは、もう一度言いますよ.Java 8から、インタフェースにも静的な方法があります.
テキストリンク:http://blog.720ui.com/2016/java_se8_01_lambda/
原文タイトル及び作者:Java 8特性詳細(一)Lambda|梁桂钊のブログ