Java 8 で Scala のような何かを使う
Java 8 では JSR 335: Lambda Expressions が取り入れられます。
これを使うと Pure Java でありながら「どう見ても Scala」というコードが書けるようになります。
主に私がメンテナンスしている ScalaFlavor4J というライブラリがあります。
https://github.com/m3dev/scalaflavor4j
Java 7 まではこんな感じで使う必要がありました。
Seq.apply(1, 2, 3, 4, 5).filter(new F1<Integer, Boolean>() { public Boolean apply(Integer i) { return i > 2; } }); // -> Seq.apply(3, 4, 5)
しかし、Java 8 ではこんなにシンプルに書けてしまいます。
Seq.apply(1, 2, 3, 4, 5).filter( (Integer i) -> i > 2 );
高階関数の引数型は省略できるので、さらにシンプルに書くとこうなります。
Seq.apply(1, 2, 3, 4, 5).filter( i -> i > 2 );
これ、Java のコードなんですよ。ちょっと感動すら覚えますね。
ちなみに Scala で書くとこうなります。
Seq(1, 2, 3, 4, 5).filter { i => i > 2 }
foldLeft の例です。これまで非常に煩雑でしたが
String s = Seq.apply('b', 'c', 'd').foldLeft("a", new FoldLeftF2<String, Character>() { public String apply(String z, Character c) { return z + c; } }); // -> s : "abcd"
これもこのように簡潔になります。
String s = Seq.apply('b', 'c', 'd').foldLeft("a", (String z, Character c) -> z + c); String s = Seq.apply('b', 'c', 'd').foldLeft("a", (z, c) -> z + c);
高階関数の処理を複数行で書く場合は、こんな感じで最後は return を省略せずに書きます。
SInt.apply(1).to(1000).par().map(i -> { print(Thread.currentThread().getId() + ","); return i * i; });
JSR 335 では functional interface を以下のように定めています。
A functional interface is an interface that has just one abstract method, and thus represents a single function contract.
ちょっとイマイチな例ですが、例えばこんなようなのを
interface F<A, R> {
R apply(A a);
}
こんな感じで受け取るメソッドであれば
class Util { static Integer toInt(String str, F<String, Integer> f) { return f.apply(str); } }
こんなのが書けます。
Integer i = Util.toInt("foo", (str) -> str.length());
あと java.lang.FunctionalInterface というアノテーションがあって、コンパイル時にそのインタフェースが妥当かをチェックすることができます。
@FunctionalInterface public interface F<A, R> { R apply(A a); R map(A a); }
このコードをコンパイルすると以下のようなコンパイルエラーになります。
F.java:1: error: Unexpected @FunctionalInterface annotation @FunctionalInterface ^ F is not a functional interface multiple non-overriding abstract methods found in interface F
以下は Java 8 が用意されている前提で試すためのサンプルです。
mkdir work cd work wget https://oss.sonatype.org/content/repositories/releases/com/m3/scalaflavor4j/1.1.0/scalaflavor4j-1.1.0.jar echo 'import com.m3.scalaflavor4j.*; import static com.m3.scalaflavor4j.Predef.*; public class Main { interface F<A, R> { R apply(A a); } static class Util { static Integer toInt(String str, F<String, Integer> f) { return f.apply(str); } } public static void main(String[] args) { println(Util.toInt("foo", (str) -> str.length())); } } ' > Main.java javac -cp scalaflavor4j-1.1.0.jar Main.java java -cp scalaflavor4j-1.1.0.jar:. Main
Java 8 のリリースが待ち遠しいですね!