java.lang.Stringにはformatメソッドが定義されている。
数値の0埋め、3桁区切り、日付の整形など、指定した形式にフォーマットする事に関してはかなり便利なメソッドである。
しかし、Androidプログラミングでこれを使用する場合は要注意。String.formatは内部でFormatterオブジェクトを生成している為かなり遅い。
例えば数値の0埋めなどは、以下のようにStringBuilderを使用して愚直に0を連結すると約6倍高速に動作する。
StringBuilderをnewせずに使いまわすテクニックを利用している事に注意。使いまわさないと速度が約半分になる。それでも十分速いが。
public class MainActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        // String.formatを使用して100000回試行.
        long timeMillis = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            String.format("%06d", i);
        }
        // かかったミリ秒を出力するイディオム. 前の時間 - (次の時間比較の為に代入しつつ現在の時間)、の全体をマイナスに. 式が左から評価される為.
        System.out.println(- (timeMillis - (timeMillis = System.currentTimeMillis())));
        // 愚直な文字列連結での100000回試行.
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 100000; i++) {
            // StringBuilderの中身を空にする.
            sb.setLength(0);
            sb.append(i);
            for (int j = 6, size = sb.length(); j > size; j--) {
                sb.insert(0, "0");
            }
            // これが無ければ約30倍高速に動作するが, 結果をStringに合わせる為仕方ない.
            sb.toString();
        }
        System.out.println(- (timeMillis - (timeMillis = System.currentTimeMillis())));
    }
}
05-08 13:10:13.250: I/System.out(18793): 6575
05-08 13:10:14.331: I/System.out(18793): 1084
日付フォーマットの例。android.text.format.Timeが使用できる状況であれば、下記のように15倍ほど高速に動作する。
使えない状況であったとしても、SimpleDateFormatをループ外でnewし、適宜formatした方が高速に動作する。
public class MainActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Date date = new Date();
        long timeMillis = System.currentTimeMillis();
        // String.formatを使用して10000回試行.
        String formatStr = "%1$tY%1$tm%1$td";
        for (int i = 0; i < 10000; i++) {
            String.format(formatStr, date);
        }
        System.out.println(- (timeMillis - (timeMillis = System.currentTimeMillis())));
        // SimpleDateFormatを使用して10000回試行.
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        for (int i = 0; i < 10000; i++) {
            sdf.format(date);
        }
        System.out.println(- (timeMillis - (timeMillis = System.currentTimeMillis())));
        // android.text.format.Timeを使用して10000回試行.
        Time time = new Time();
        time.set(date.getTime());
        formatStr = "%Y%m%d";
        for (int i = 0; i < 10000; i++) {
            time.format(formatStr);
        }
        System.out.println(- (timeMillis - (timeMillis = System.currentTimeMillis())));
    }
}
05-08 13:40:49.091: I/System.out(19604): 2948
05-08 13:40:50.322: I/System.out(19604): 1230
05-08 13:40:50.502: I/System.out(19604): 186
業務では目に見えてこのようなループ処理が行われている事が少ないが、メソッド内でString.formatを使用しており、それが暗に何百回も呼ばれている、という事がままある。
 
0 件のコメント:
コメントを投稿