String#formatの実力
はてなに登録して、記念すべき最初の投稿がこんなものでいいのだろうか・・・・。
ちょっと古いが、文字列を整形するために、Java1.5で使えるようになったString#formatの速度検証を行ってみた。
今回の検証は以下の通り
「1ブロック10バイトの半角スペースを10000000個ファイルに出力する。」
10バイトの半角スペースを以下の4通りの方法で実装した。
- あらかじめ10バイトのスペースを定数で用意
- 毎回10バイトのスペースを変数で生成して用意
- StringBufferクラスでスペースをappendする処理を10回ループさせて用意
- String#formatを使用(フォーマット:%10s)して10バイトのスペースの変数を用意
測定結果は以下のとおり。
No | 方式 | 所要時間 |
---|---|---|
1 | 定数 | 1520ms |
2 | 変数 | 1471ms |
3 | StringBuffer使用 | 5351ms |
4 | String#format使用 | 33490ms |
String#formatおそっ!!!!
参考までに今回作成したソースを載せておく。
package sample; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.Date; /** * String#formatのパフォーマンスを測定するクラス * @author @labo * */ public class StringFormatPerformanceChecker { /* ループ回数 */ private static final int COUNT = 10000000; /* 10バイトのスペース定数 */ private static final String STR = " "; /** * メインメソッド * @param args 使用しません */ public static void main(String[] args) { StringFormatPerformanceChecker p = new StringFormatPerformanceChecker(); System.out.println("static : " + p.new StaticChecker("static").getTime()); System.out.println("variable : " + p.new VariableChecker("variable").getTime()); System.out.println("dynamic : " + p.new DynamicChecker("dynamic").getTime()); System.out.println("string format : " + p.new StringFormatChecker("stringformat").getTime()); } /** * パフォーマンスチェックの抽象クラス * @author @labo * */ private abstract class Checker { /* ファイル出力オブジェクト */ private BufferedWriter bw = null; /** * コンストラクタ * * @param fileName ファイル名(ファイル名 + 「.txt」でファイル名となる) */ public Checker(String fileName) { try { bw = new BufferedWriter(new FileWriter(new File("d:/" + fileName + ".txt"))); } catch (IOException e) { e.printStackTrace(); } } /** * 時間を計測するクラス * @return 経過時間(ms) */ public long getTime() { // 開始時刻 Date start = new Date(); try { for (int i=0; i<COUNT; i++) { // 10000000回ループ // 10バイトのスペースを出力 bw.write(getString()); } } catch (IOException e) { e.printStackTrace(); } finally { try { bw.close(); } catch (IOException e) { e.printStackTrace(); } } // 終了時刻 Date end = new Date(); // 終了時刻 - 開始時刻をlongで返却(経過ms) return end.getTime() - start.getTime(); } /** * 10バイトのスペース取得処理 * このメソッドを各々の方式で実装する * @return 10バイトのスペース文字列 */ protected abstract String getString(); } /** * 定数を用いたパフォーマンス測定クラス * @author @labo * */ private class StaticChecker extends Checker { /** * コンストラクタ * @param fileName * @see Checker */ public StaticChecker(String fileName) { super(fileName); } /** * 定数文字列を返却する */ @Override protected String getString() { return STR; } } /** * 変数を用いたパフォーマンス測定クラス * @author @labo * */ private class VariableChecker extends Checker { /** * コンストラクタ * @param fileName * @see Checker */ public VariableChecker(String fileName) { super(fileName); } /** * 変数文字列を返却する */ @Override protected String getString() { return " "; } } /** * StrngBufferを用いたパフォーマンス測定クラス * @author @labo * */ private class DynamicChecker extends Checker { /** * コンストラクタ * @param fileName * @see Checker */ public DynamicChecker(String fileName) { super(fileName); } /** * StringBufferで文字列を生成して返却する */ @Override protected String getString() { StringBuffer sb = new StringBuffer(); for (int j=0; j<10; j++) { sb.append(" "); } return sb.toString(); } } /** * String#formatを用いたパフォーマンス測定クラス * @author @lLabo * */ private class StringFormatChecker extends Checker { /** * コンストラクタ * @param fileName * @see Checker */ public StringFormatChecker(String fileName) { super(fileName); } /** * String#formatで文字列を生成して返却する */ @Override protected String getString() { return String.format("%10s", ""); } } }