2006/10/25

[Java]String.intern()

JavaのStringクラスに、intern()というメソッドがある。
APIドキュメントの説明を要約すると、StringのインスタンスはVMが管理していて、str.intern()とすることにより、内容が同じ文字列があった場合にはそのインスタンスを返してくれるらしい。
これがどんなところに使われているかというと、クラス内の文字リテラル("foo"のように記述している箇所)で使用され、文字リテラルのインスタンスはVM上で同一になるようになっている。

同一インスタンスになるとうれしいことは、メモリの節約になることと、String.equals()が高速になること。例として挙げられそうなのは、読み込んだプロパティファイルをSingletonで保持している場合など、そのインスタンスが頻繁に比較される箇所。
設定ファイルを読み込んだ後にキーと値にString.intern()をかけつつHashMapにコピーしておけば、設定値名の定数などと同じインスタンスになってくれる可能性がある。

サンプルコード。
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class Config {
    private static final Map<String, String> PROPERTIES;
    static {
        Properties prop = new Properties();
        InputStream input = Config.class.getResourceAsStream("foo");
        try {
            if (input != null) {
                prop.load(input);
                input.close();
            }
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }

        Map<String, String> copy = new HashMap<String, String>(prop.size());
        for (Object key : prop.keySet()) {
            String asStr = (String) key;
            copy.put(asStr.intern(), prop.getProperty(asStr));
        }
        PROPERTIES = Collections.unmodifiableMap(copy);
    }

    public static String get(String key) {

        return PROPERTIES.get(key);
    }
}

パフォーマンス上のポイントは以下の三点。エラー処理は適当。

  1. キーと値をintern
  2. PropertiesをHashMapにコピー(不要なsynchronizedをやめるため)
  3. 変更する予定がないので、変更不可のMapでラップ

定数をキーとして指定することが多い場面では、処理速度がだいぶ違う。
注意が必要なのは、intern自身はあまり早い処理ではないので、頻繁に作成されるStringのインスタンスに対して逐次internしていると、逆に遅くなること。そして、上記の定数としての文字列がinternより前に読み込まれていないと、その定数には効果がないことだ。

ラベル:

0 件のコメント:

コメントを投稿

登録 コメントの投稿 [Atom]

<< ホーム