Java標準ライブラリを学ぶ #1

Javaエンジニア養成読本を読んで気になったところをまとめていこうと思います。

今回は第4章。

文字列を扱う

文字列を比較するときに気をつけること

  • 「==」は使用できない

Stringクラスはnew演算子インスタンスを生成することが稀なため、インスタンスの識別が曖昧になりがち。
文字列リテラルは常にインスタンスを生成するわけでなく、生成済みの場合は同じインスタンスが共有される。Stringクラスのインスタンスをnew演算子で各々生成すれば、同じ文字列であっても、==演算子でfalseを返す。
文字列の一致を検証したい場合は、equals()メソッドを使用する。

文字列の連結で知っておくべきこと

+で文字列の連結が可能だが、連結されるたびに新たなインスタンスが生成される。そのため、連続して連結する場合は、StringBuilderクラスを使用するのが一般的。
Java SE8 にてStringクラスに文字列を区切り文字つきで連結するjoin()メソッドが追加された。

Stringクラスはイミュータブル

replace()メソッドなどの状態を変化させそうなメソッドも自身のインスタンスは変更せず、別のインスタンスを返すようになっている。

実際にいろんな文字列連結パターンの所要時間出して見ました。コードはこれ。
次のブログから知恵をお借りしました。
calms.hatenablog.com

public class TestString {
	public static void main(String[] args) {
		String val1 = "abcde";
		String val2 = "fghij";
		String val3 = "klmno";
		String val4 = "pqrst";
		String val5 = "uvwxyz";

		long startTime1 = System.currentTimeMillis();
		String message1 = null;
		for (int i = 0; i < 100000000; i++) {
			message1 = val1 + val2;
			message1 += val3;
			message1 += val4;
			message1 += val5;
		}
		long endTime1 = System.currentTimeMillis();
		System.out.println("+で連結の所要時間(ms) : " + (endTime1 - startTime1));

		long startTime2 = System.currentTimeMillis();
		String message2 = null;
		for (int i = 0; i < 100000000; i++) {
			StringBuilder buf2 = new StringBuilder();
			buf2.append(val1);
			buf2.append(val2);
			buf2.append(val3);
			buf2.append(val4);
			buf2.append(val5);
			message2 = buf2.toString();
		}
		long endTime2 = System.currentTimeMillis();
		System.out.println("StringBuilderで連結の所要時間(ms) : " + (endTime2 - startTime2));

		long startTime3 = System.currentTimeMillis();
		String message3 = null;
		StringBuilder buf3 = new StringBuilder();
		for (int i = 0; i < 100000000; i++) {
			buf3.setLength(0);
			buf3.append(val1);
			buf3.append(val2);
			buf3.append(val3);
			buf3.append(val4);
			buf3.append(val5);
			message3 = buf3.toString();
		}
		long endTime3 = System.currentTimeMillis();
		System.out.println("StringBuilder&setLength(0)で連結の所要時間(ms) : " + (endTime3 - startTime3));

		long startTime4 = System.currentTimeMillis();
		String message4 = null;
		for (int i = 0; i < 100000000; i++) {
			StringBuilder buf4 = new StringBuilder(val1);
			buf4.append(val2);
			buf4.append(val3);
			buf4.append(val4);
			buf4.append(val5);
			message4 = buf4.toString();
		}
		long endTime4 = System.currentTimeMillis();
		System.out.println("StringBuilder&new StringBuilder(val1)で連結の所要時間(ms) : " + (endTime4 - startTime4));

		long startTime5 = System.currentTimeMillis();
		String message5 = null;
		for (int i = 0; i < 100000000; i++) {
			message5 = val1 + val2 + val3 + val4 + val5;
		}
		long endTime5 = System.currentTimeMillis();
		System.out.println("+で一気に連結の所要時間(ms) : " + (endTime5 - startTime5));
	}
}

ちなみに結果は、こんな感じです。
=======
+で連結の所要時間(ms) : 6387
StringBuilderで連結の所要時間(ms) : 7995
StringBuilder&setLength(0)で連結の所要時間(ms) : 4869
StringBuilder&new StringBuilder(val1)で連結の所要時間(ms) : 8711
+で一気に連結の所要時間(ms) : 2991
=======

5番目の連結方法が圧倒的に早いです!