皆さん、ソースコードは下手な小説より楽しいですよヽ( ´-`)ノ。今日はJakarta commonsより、padding()です。文字padCharをrepeat回だけ繰り返した文字列を返すだけの関数です。
private static String padding(int repeat, char padChar) { // be careful of synchronization in this method // we are assuming that get and set from an array index is atomic String pad = PADDING[padChar]; if (pad == null) { pad = String.valueOf(padChar); } while (pad.length() < repeat) { pad = pad.concat(pad); } PADDING[padChar] = pad; return pad.substring(0, repeat); }
はて? と思えれば、きちんとソースを読めてる人(笑)。繰り返しの実装するだけなのに妙に複雑ですね。特に、String PADDING[]。こいつの宣言を探すと、序盤にこんな摩訶不思議なコードが出てきます。
private static final String[] PADDING = new String[Character.MAX_VALUE]; static { // space padding is most common, start with 64 chars PADDING[32] = " "; }
PADDINGは文字列の配列で、文字の個数ぶんだけ領域があるみたいです。じゃあ、32番目の要素だけ初期化してるのはなぜ? しかも空白64byte。
これは、関数内のifとwhileを見ると答えが見えてきます。PADDING配列を調べて、中身がなければ作成、個数が足りなければ追加してます。このロジックは・・・そう、キャッシュですね。毎回padding文字列を繰り返すのは無駄なので、文字をつないだものをキャッシュに突っ込んでおいて、そのキャッシュからsubstring()で返してるわけです。
で、staticの中では、最もよく使われるスペース*1の64個分のpadding文字列を確保していたってことです。深い実装ですねー。
でも、ここで改善点とかも浮かんできます。特に、whileでの追加部分。そんなにパフォーマンスにこだわるなら、StringBuilderを使ってもいい気がします。後、1文字ずつキャッシュを拡張するんじゃなく、64byteずつ拡張するとか。
それと、この実装はキャッシュに文字列を突っ込むので、repeatに大きな数を与え過ぎると大変なことになります。生成される巨大な文字列を、利用者はパッと使ってすぐ捨てるつもりでも、キャッシュにはいつまでも残ってしまうと言うことになります。
まあ、用途としてはスペースを5〜10個つけるってくらいを想定しているんで、こんな実装なんでしょう。巨大な文字列や他の文字を追加するのに利用することは、あまり想定していないってことですね。
*1:0x20=32 ←2009-04-14 追記