今更Java8を試してみるの巻。
最近実装仕事から離れていたのでどんどんわからなくなっていくことを危惧。特にラムダ式はちゃんと知っておかないと今後コードを『読む』ことすらできなくなりそうなので…。

ラムダ式って

JavaではJava8から追加されたもので、C#なんかには前からあったみたいだけどそれも知らない。
なにか新しい特別な機能と言うよりは記述方法がかなり略式になるというメリットがある。

Runnableとか、「メソッドをひとつしか持たないインタフェース」の実装を行う時にこれよりも簡素で本質的な記述が出来るようになる。
ちなみに「メソッドをひとつしか~」は、「関数型インタフェース」と言うそうです。知りませんでした。


例えば、文字列の出来るだけ後ろの方に「a」が出てくる順に並べると言うソートがあったとすると(そんなの必要ないだろうという突っ込みは…)

public class Test {
	public static void main(String[] args){
		List<String> list = Arrays.asList("Tokyo","Kanagawa","Chiba");
		Collections.sort(list,new Comparator<String>(){
				@Override
				public int compare(String s1,String s2){
					return s1.lastIndexOf('a') - s2.lastIndexOf('a');
				}});
		for(String str:list){
			System.out.println(str);
		}
	}
}

無名クラスをnewしてやることで記述できるが、ロジックとは関係のない定型的な部分が多い。
ラムダ式を使うと…

public class Test {
	public static void main(String[] args){
		List<String> list = Arrays.asList("Tokyo","Kanagawa","Chiba");
		list.sort((String s1, String s2) -> s1.lastIndexOf('a') - s2.lastIndexOf('a'));
		for(String str:list){
			System.out.println(str);
		}
	}
}

こんなにすっきりします。

ラムダ式の文法

ラムダ式は以下の文法に従って記述します。

( 実装するメソッドの引数 ) -> { 処理 }

最初の例だと
「public int compare(String s1,String s2)」が「(String s1, String s2)」
になった感じですね。この時さらに、型の指定を外して「(s1,s2)」だけでもOKだったりします。

list.sort((s1, s2) -> s1.lastIndexOf('a') - s2.lastIndexOf('a'));

もうこうなるとJavaっぽくないですね。どこのスクリプト言語だよと。
ちなみにこの例だと式が1行なのでreturnがありませんが、複数行のロジックを「;」でつないだ場合は最後にreturnをちゃんと入れてあげる必要があります。

関数型インタフェース

Java8でjava.util.functionパッケージの下にゴロゴロと汎用的な関数型インタフェースが追加されていて、大体のことはこれを使えばよさそう。
でも結局のところ、関数型インタフェースの実体を生成してるわけなので、用意されているインタフェースが合わなければ自分で@FunctionalInterfaceアノテーションをつけてインタフェースを宣言すれば何でもできる。

@FunctionalInterface
public interface MyFunction {
  public int multi(int i1, int i2, int i3);
}

public MyFunction function = (i1, i2, i3) -> i1 * i2 * i3;
int result = function.multi(1, 2, 3);

ラムダ式の導入で型宣言がなくなったり、なんだかスクリプトチックな記述が出来るようになり、個人的には読みにくくなったなぁと。
結局旧来の書き方でも問題はないし、変にコンパイルエラーではまるくらいなら慣れてる方法で書いてしまうって人も多そうで、プロジェクトでJava8導入するときはきちんとソース管理できる人が見てやらないとカオスになりそうだな、ってのが感想です。