今回はラムダ式についてです。
(もうラムダ・メソッド参照に関わらないネタが思い付かないです。)
ラムダ式の書き方については他で紹介してるページを参考にしてもらうとして、
ここではラムダ式1を書いた場合どういうインスタンスが生成されるか確認しておきたいです。
参考:http://www.oracle.com/technetwork/jp/articles/java/architect-lambdas-part2-2081439-ja.html
またソートを例にします。
#ソートをラムダ式1に置き換える
/**
* 大文字小文字無視したソート
*/
public static void sort() {
List<String> list = new ArrayList<>(Arrays.asList("C", "b", "A"));
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
});
System.out.println(list);//[A, b, C]
}
がラムダ式1だと、
public static void sort() {
List<String> list = new ArrayList<>(Arrays.asList("C", "b", "A"));
list.sort(String::compareToIgnoreCase);
System.out.println(list);//[A, b, C]
}
わー短く書けるね。って話ではなくてですね、
この2つがどういうインスタンス生成されるか確認したいという話です。
#Comparatorのインスタンス数を確認してみる
インスタンスを確認するためComparatorを変数に一旦格納するのと、
これらのロジックを10回実行してみます。
/**
* Comparatorのインスタンス生成数確認
*/
public static void sortAndCheck() {
Set<Comparator<String>> set = new HashSet<>();
for (int i = 0; i < 10; i++) {
List<String> list = new ArrayList<>(Arrays.asList("C", "b", "A"));
Comparator<String> comparator = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
};
set.add(comparator);
Collections.sort(list, comparator);
System.out.println(i + 1 + " " + list);
}
System.out.println("count:" + set.size());//set.size()は10
}
public static void sortAndCheck() {
Set<Comparator<String>> set = new HashSet<>();
for (int i = 0; i < 10; i++) {
List<String> list = new ArrayList<>(Arrays.asList("C", "b", "A"));
Comparator<String> comparator = String::compareToIgnoreCase;
set.add(comparator);
Collections.sort(list, comparator);
System.out.println(i + 1 + " " + list);
}
System.out.println("count:" + set.size());//set.size()は1
}
で実行するとラムダ使わないほうはインスタンスが10個生成されてしまいます。
それに比べてラムダ式1の方は1個だけです。
つまりラムダ使わずにラムダ式1の方を再現すると正しくは下記のようになります。
#ラムダ式1をラムダ式じゃない記述に置き換える
private static final Comparator<String> comparatorIgnoreCase = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
};
/**
* 大文字小文字無視したソート
*/
public static void sort() {
List<String> list = new ArrayList<>(Arrays.asList("C", "b", "A"));
Collections.sort(list, comparatorIgnoreCase);
System.out.println(list);//[A, b, C]
}
/**
* Comparatorのインスタンス生成数確認
*/
public static void sortAndCheck() {
Set<Comparator<String>> set = new HashSet<>();
for (int i = 0; i < 10; i++) {
List<String> list = new ArrayList<>(Arrays.asList("C", "b", "A"));
Comparator<String> comparator = comparatorIgnoreCase;
set.add(comparator);
Collections.sort(list, comparator);
System.out.println(i + 1 + " " + list);
}
System.out.println("count:" + set.size());//set.size()は1
}
ここまで書くぐらいならラムダ式書いた方が明らかにスマートですね。
#まとめ
ラムダ式は単純置き換え元よりは明らかにインスタンスが節約できるという話でした。
※今回はインスタンス節約できる例で書いただけで必ずそうなるわけではありません。
条件まとめるのめんどくさいので書きませんが、基本的にはやっぱり節約できるはずです。
その5につづく。(ネタ考えます)
その1:Java8が好きになる話(StreamAPIの話はしない) その1 Map#computeIfAbsentとList#sort
その2:Java8が好きになる話(StreamAPIの話はしない) その2 Optional#map
その3:Java8が好きになる話(StreamAPIの話はしない) その3 インターフェースのデフォルト実装