htsign's blog

ノンジャンルで書くつもりだけど技術系が多いんじゃないかと思います

Java5 での開発のつらみをやわらげる tips

仕事で Java5 の案件がきました。
このご時世に Java5 とか負の遺産以外のなにものでもないですが、仕事なので仕方ありません。

拡張for文とか可変長引数とかアノテーションとかジェネリクスとか、それ以前と比べればかなりマシなものの、
現代的なプログラミング言語の数々と比べてしまうとゴミカスだと思います。

何よりツラいのが、高階関数がないこと。
高階関数がないので副作用を抑えるコードを書きづらいのです。
仕方がないのでjava.lang.reflect.Methodクラスを使います。

こんなクラスを書きました。

追記 (2017/11/16 11:23)

長くて記事の本質が見えにくくなってしまうので、Gistに移してリンクにしました。
It provides some functional programming feature to Java5 · GitHub

これはこれで毎度Methodクラスのインスタンスを作らなくてはならないとか型チェックが効かず実行時エラーの恐れがあるとか別のつらみがありますし、
内部でもインスタンス作りまくったりしてて非常にパフォーマンスは悪いと思いますが、
引き換えにちょっとだけ関数型ちっくに書くことができるようになりました。

import java.io.PrintStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

class Example {
    public static void main(String[] args) {
        // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 の ArrayList
        final List<Integer> list = new ArrayList<Integer>();
        for (int i = 0; i < 10; ++i) {
            list.add(Integer.valueOf(i));
        }
        
        try {
            final Method isEven = Example.class.getMethod("isEven", int.class);
            final Method stringValueOf = String.class.getMethod("valueOf", int.class);
            final Method println = PrintStream.class.getMethod("println", String.class);

            // メソッドチェイン的な
            new IterableUtils<Integer>(list)          // IterableUtils インスタンスに変換
                .filter(isEven)                       // 2 で割り切れる数のみにフィルタ
                .map(String.class, stringValueOf)     // String 型にマッピング
                .forEach(System.out, println);        // 一つずつ System.out に出力 ==> 0, 2, 4, 6, 8
            
            final Method plus = Example.class.getMethod("plus", int.class, int.class);
            
            // モジュールそのまま呼ぶ感じ
            // 畳み込んで合計
            System.out.println(IterableUtils.reduce(list, 0, plus));  // ==> 45
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static boolean isEven(int i) {
        return i % 2 == 0;
    }
    
    public static int plus(int lhs, int rhs) {
        return lhs + rhs;
    }
}

うん、問題なく動いてるように見えますね。
これでゴテゴテのオブジェクト指向言語に無理矢理関数型パラダイムを持ち込むことができました。

この手のライブラリってどっかにありそうなもんなんですが、探してもそれらしいの見つからなかったんですよね…。