メソッドにサフィックス付けた奴出てこい2


はじめに

この記事はメソッドにサフィックス付けた奴出てこいの続編になります。
少し端折る部分もありますことご了承ください。

気になっていたこと

前回の記事はただのストレス発散であったが、パフォーマンスが気になっていました。
リフレクションAPIへのアクセスがどれくらい足を引っ張るのか知りたいのです。

これでどうや

とりあえず時間吐かせました。

suffixMethodsCaller.java
package suffixMethodsCall;

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

public class suffixMethodsCaller {

    /**
     * <pre>
     * suffixMethodsに含まれる、suffix付きのgetterを全て実行し、
     * 冒頭のmatchTargetCodeが含まれるか検証する.
     * </pre>
     */
    public static void main(String[] args) {

        // 計測スタート
        long measureStart = System.currentTimeMillis();

        // マッチング対象の文字列
        String matchTargetCode = "J";
        // suffix付きのメソッドから取得できたコードリスト
        List<String> codeList = new ArrayList<String>();

        // クラス、メソッドを文字列で指定
        suffixMethods sm = new suffixMethods();
        String clazz = sm.getClass().getName();
        String baseSuffixMethod = "getReturnCode";
        int suffixPartStart = 1;
        int suffixPartEnd = 10;

        // リフレクションを利用して、suffix付きのメソッドを実行
        try {
            Class<?> c = Class.forName(clazz);
            Object myObj = c.newInstance();

            // suffix部分をループさせてコードリストに突っ込む
            for ( ; suffixPartStart <= suffixPartEnd; suffixPartStart++) {
                // 実行メソッドの設定
                Method m = c.getMethod(baseSuffixMethod + String.format("%02d", suffixPartStart));
                // コードリストに詰め込む
                codeList.add(m.invoke(myObj).toString());
            }
        } catch(ReflectiveOperationException e) {
            e.printStackTrace();
        }

        // マッチング対象の文字列が、suffix付きメソッドの実行結果リストに含まれるのかboolで出力
        System.out.println(codeList.contains(matchTargetCode));

        // 計測終わり!
        long measureEnd = System.currentTimeMillis();
        System.out.println((measureEnd - measureStart) + "ms");
    }
}
実行結果
true
44ms

なるほどなるほど。
では次、ダサめ行ってみましょうか。

suffixMethodsCaller2.java
package suffixMethodsCall;

public class suffixMethodsCaller2 {

    /**
     * <pre>
     * suffixMethodsに含まれる、suffix付きのgetterを全て実行し、
     * 冒頭のmatchTargetCodeが含まれるか検証する.
     * </pre>
     */
    public static void main(String[] args) {

        // 計測スタート
        long measureStart = System.currentTimeMillis();

        // マッチング対象の文字列
        String matchTargetCode = "J";

        suffixMethods sm = new suffixMethods();

        // マッチング対象の文字列が、suffix付きメソッドの実行結果リストに含まれるのかboolで出力
        System.out.println(sm.getReturnCode01().equals(matchTargetCode) || sm.getReturnCode02().equals(matchTargetCode)
                || sm.getReturnCode03().equals(matchTargetCode) || sm.getReturnCode04().equals(matchTargetCode)
                || sm.getReturnCode05().equals(matchTargetCode) || sm.getReturnCode06().equals(matchTargetCode)
                || sm.getReturnCode07().equals(matchTargetCode) || sm.getReturnCode08().equals(matchTargetCode)
                || sm.getReturnCode09().equals(matchTargetCode) || sm.getReturnCode10().equals(matchTargetCode));

        // 計測終わり!
        long measureEnd = System.currentTimeMillis();
        System.out.println((measureEnd - measureStart) + "ms");
    }
}
実行結果
true
1ms

え。。。?まじで?
こんなに差が出るんですね。

ちょっと気になったのでもう一つ。悪文ですが真偽を逆にして、なにか変化あるのか見たいです。
精度上げてnanoTimeにしました。

suffixMethodsCaller3.java
package suffixMethodsCall;

public class suffixMethodsCaller3 {

    /**
     * <pre>
     * suffixMethodsに含まれる、suffix付きのgetterを全て実行し、
     * 冒頭のmatchTargetCodeが含まれるか検証する.
     * </pre>
     */
    public static void main(String[] args) {

        // 計測スタート
        long measureStart = System.nanoTime();

        // マッチング対象の文字列
        String matchTargetCode = "J";

        suffixMethods sm = new suffixMethods();

        // マッチング対象の文字列が、suffix付きメソッドの実行結果リストに含まれるのかboolで出力
        System.out.println(!sm.getReturnCode01().equals(matchTargetCode) && !sm.getReturnCode02().equals(matchTargetCode)
                && !sm.getReturnCode03().equals(matchTargetCode) && !sm.getReturnCode04().equals(matchTargetCode)
                && !sm.getReturnCode05().equals(matchTargetCode) && !sm.getReturnCode06().equals(matchTargetCode)
                && !sm.getReturnCode07().equals(matchTargetCode) && !sm.getReturnCode08().equals(matchTargetCode)
                && !sm.getReturnCode09().equals(matchTargetCode) && !sm.getReturnCode10().equals(matchTargetCode));

        // 計測終わり!
        long measureEnd = System.nanoTime();
        System.out.println((measureEnd - measureStart) + "ns");
    }
}

読みにくいったらないですね。

実行結果
false
1127314ns

へー。
一個前のもナノオーダーにしてみます。

実行結果
true
1100219ns

おー。
何度か実行してみましたが、結果はほぼ同じでした。
可読性の優劣だけなんですね。
勉強になりました。

しかしリフレクションを利用した際の遅さには驚愕です。
for文があるからかな?と思ってループをなくしても結果は同じでした。

さいごに

リフレクションは業務アプリケーションではおすすめできないようですが、
内部向けのUtil等にはとても面白く使えるので個人的には気に入っています。

ストレス発散から始まったこの記事ですが、実際に手を動かしてみるとすごく勉強になりました。
どなたかの参考になれば幸いです。