【Java】StringとStringBufferの使い分け

当ページのリンクには広告が含まれている可能性があります。
StringとStringBuffer

こんにちは。ユーキです。

今日は、StringとStringBuffferの使い分けの目安について、お話したいと思います。

目次

Stringクラスとは

文字列を扱うクラスです。Javaで文字列を扱う場合には、避けては通れない基礎中の基礎となるクラスです。多くのメソッドの引数にも指定されています。

Javaを学習する際でも、プリミティブ型(基本型)と並び立つクラスです。

StringBufferクラスとは

Stringクラスの拡張と考えれるのが、一番理解しやすいと思います。

Java API リファレンスによると、「スレッドセーフな可変の文字列」と表現されています。

どういうことなのかは、次で説明をしていきたいと思います。

StringクラスとStringBufferクラスの違い

StringBufferは、「スレッドセーフな可変の文字列」でした。では、Stringクラスはどうかというと、Stringクラスは固定の文字列となります。

ん?と思ったあなた。わかってますね。そうです。Stringクラスも文字の連結処理は行うにも関わらず、固定の文字列とはどういうことなのか。

実際にコードを書いて説明します。

String txt1 = new String("Good");
txt1 = txt1 + "Morning";
txt1 = txt1 + ":おはよう!";
String txt2 = "Good" + "Morning" + ":おはよう!";
StringBuffer sb = new StringBuffer();
sb.append("Good");
sb.append("Morning");
sb.append(":おはよう!");

いずれも、「GoodMorning:おはよう!」という文字列を生成しています。
コード上では、どの書き方をしても得られる結果は同じです。違うのは、メモリの使われ方です。

実はStringオブジェクトは、文字連結をする際に新しいオブジェクトを内部で生成しています。
どういうことかというと、「txt1 = txt1 + “Morning”;」を実行すると、内部では以下のように処理をされます。

txt1 = new String(txt1 + "Morning");

新しいオブジェクトが生成されています。つまり、その生成されたオブジェクト分だけメモリが使用されることとなります。

これを繰り返すと、無駄なメモリを消費してしまうため、文字連結をする際にはStringBufferが推奨されます。StringBufferであれば、新たなオブジェクトが生成されることなく、文字を連結していくことが可能です。

なお、「String txt2 = “Good” + “Morning” + “:おはよう!”;」このコードについては、生成されるStringオブジェクトは1つだけになるため、さほど問題でありません。

検証

では、検証コードを書いて検証してみましょう。

public static void main(String[] args) {
	writeMemory("実施前:");
	
	String str = "";
	String txt1 = new String();
	for(int i = 0; i < 10000; i++) {
		txt1 = txt1 + "Good";
		txt1 = txt1 + "Morning";
		txt1 = txt1 + ":おはよう!";
	}
	writeMemory("String txt1");
	
	StringBuffer sb = new StringBuffer();
	for(int i = 0; i < 10000; i++) {
		sb.append("Good");
		sb.append("Morning");
		sb.append(":おはよう!");
	}
	writeMemory("StringBuffer");
}

public static void writeMemory(String type) {
    long free =  Runtime.getRuntime().freeMemory() / 1024/ 1024;
    long total = Runtime.getRuntime().totalMemory() / 1024/ 1024;
    long used =  total - free;
    System.out.println("使用メモリ量:" + used + "MB" + " (" + type + ")");
}

5回実行した結果は以下のようになりました。

回数String (MB)StringBuffer(MB)
12052
21521
31072
41401
52731
実行結果

一目瞭然ですね。

繰り返し処理内で、Stringでの文字連結は危険ということがよくわかりますね。

どう使い分ける

上記を踏まえ、Stringの文字連結が危険な書き方であることがわかりました。では、どのように使い分けるか。

個人の好みもありますが、私自身は、連結処理が3行以上になるような場合は、StringBufferを使うようにしています。

また、繰り返し処理で、文字連結する際は、基本的にはStringBufferを選択するのが無難でしょう。

StringBuilderはどうなの?

Java1.5から登場したクラスです。

API リファレンスによると、「ほとんどの実装で高速に実行される」とあります。StringBufferの代替として使用できるようになっているそうですが、「複数のスレッドで使用するには安全ではありません。このような同期が必要な場合は、StringBufferを使用することをお薦めします。」とも記載されています。

私は実務でこのクラスが実装されているのをみたことはありません。個人的には、StringBufferを使用しておくのが無難なように思います。

最後に

実行される処理は同じでも、メモリの使い方が異なるため、使い分けが必要となります。

実務では、100万回繰り返すというような処理を行うこともありますので、こういったメモリの扱われ方も知って、メモリリークを行さないコードを書くように心がけていただけると幸いです。

スポンサーリンク
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

旅好き職業プログラマ。文系大学卒業後、ITソフトウエア開発会社に勤務してプログラミング言語を学ぶ。現在は転職し、プロジェクトマネージャ的ポジションで生産管理システムの開発にあたる。
得意言語は、VB、VB.NET、C#.NET、Java、SQLなど。

目次