ScalaのmapをJavaでやりたかった…。

Scalaのmap

Scalaでとにかく便利なのはコレクションに対するmapのメソッド。

scala> List(1,2,3,4,5).map { i => (i + 100).toString }
res0: List[java.lang.String] = List(101, 102, 103, 104, 105)

Listにmapで関数を渡すと、各要素を引数として関数を評価し、その結果をコレクションで返してくれます。上記の例では入力がInt、出力がStringの関数を渡して、結果の文字列をListで受け取っています。

Javaでやりたかった…

とりあえずJavaのコレクションを継承したクラスにmapを持たせようと思ったがこんなことになった。
Scalaみたいにできるだけ短く書きたい。」
「関数を定義する為だけにクラスを増やしたくない」

public interface C<I,O> {
	public O exec(I i);
}

まずは関数定義の為に短い名前のインタフェースを定義。
これを実装したインスタンスを使用したいその場で作成して投げる。
汎用的なものはちゃんとクラス定義しておく。

import java.util.ArrayList;

public class ArrayListW<T> extends ArrayList<T> {
	public <O> ArrayListW<O> map(C<T,O> function) {
		ArrayListW<O> result = new ArrayListW<O>();
		for(T t : this) result.add(function.exec(t));
		return result;
	}
}

そしてJavaArrayListを継承したクラスを作成し、mapメソッドを作成。

public class Test {
	public static void main(String[] args) {
		ArrayListW<Integer> foo;
		ArrayListW<String> bar;
		C<Integer,String> mapper = new C<Integer,String>(){
			public String exec(Integer i) {
				return new Integer(i+100).toString();
			}
		};
		foo = new ArrayListW<Integer>();
		for(int i=1; i<=5; i++) foo.add(i);
		bar = foo.map(mapper);
		System.out.println(bar);
	}
}

適当なお試しコード。やっぱり長ったらしくなった…。

$ java Test
[101, 102, 103, 104, 105]

まあ動きは想定通りだけど、やっぱり使いづらそう。
Java標準のクラスにもScalaのmap欲しいけど、関数を渡せないからなぁ…。
Callbackインタフェースを使用してDBを操作するようなAPISeasar2やSpringにはあるのに…。
パイプライン処理のような書き方はなかなかできないらしいな。