うさぎ組

ソフトウェア開発、チームによる製品開発、アジャイル、ソフトウェアテスト

IntegerとBigDecimalはnewしないほうがいい

タイトルについてTwitterで以前に同じようなことをツイートしましたが、まとめておこうということで。


ちなみに調べたのはSun JDK 1.6.21です。


結論から言うとIntegerとBigDecimalインスタンスを取得する時はnewではなくvaluesOfを使おう!ってことです。

Integer i = new Integer(10);
BigDecimal b = new BigDecimal(10);


ではなく

Integer i = Integer.valueOf(10);
BigDecimal b = BigDecimal.valueOf(10);

1.Integer

Integerのコンストラクタの実装を見ると次の感じ。

    public Integer(int value) {
	this.value = value;
    }


で、valueOfを見ると次の実装。

    public static Integer valueOf(int i) {
        if(i >= -128 && i <= IntegerCache.high)
            return IntegerCache.cache[i + 128];
        else
            return new Integer(i);
    }


-128からIntegerCache.highまで数値はキャッシュの配列を返すようになっています。
上限値のIntegerCache.highというのはJavaVMの起動時の引数で変更できるようです。
ちなみにIntegerCacheはこんな感じのIntegerのstatic inner classです。

    private static class IntegerCache {
        static final int high;
        static final Integer cache[];

        static {
            final int low = -128;

            // high value may be configured by property
            int h = 127;
            if (integerCacheHighPropValue != null) {
                // Use Long.decode here to avoid invoking methods that
                // require Integer's autoboxing cache to be initialized
                int i = Long.decode(integerCacheHighPropValue).intValue();
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - -low);
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
        }

        private IntegerCache() {}
    }


どのバージョンからこのような実装であったかは調べていませんが、
常にInteger.valueOf(10)のようにしておけばJDKによってはキャッシュが使われる可能性があるよ。
ということでnewではなくvalueOf()を使うほうがいいと思います。


2.BigDecimal

コンストラクタの実装は次のよう。

    public BigDecimal(int val) {
	intCompact = val;
    }


valueOfはこんな感じ

    public static BigDecimal valueOf(long val) {
        if (val >= 0 && val < zeroThroughTen.length)
            return zeroThroughTen[(int)val];
        else if (val != INFLATED)
            return new BigDecimal(null, val, 0, 0);
        return new BigDecimal(BigInteger.valueOf(val), val, 0, 0);
    }


でこのzeroThroughTenっていうのがキャッシュになっていて名前のとおり0から10までのキャッシュになっています。
ということでBigDecimalについてもvalueOfにしておくとキャッシュが使われる可能性があるのでnewではなくvalueOf()で。


id:bleis-tiftさんにも言われましたが、JDK実装依存なので、
範囲によって「〜のときはnew,〜のときはvalueOf」とするのではなくって、常にvalueOfでインスタンス生成するようにしておくのがいいですね。