文字列、つまり String型インスタンスは、生成したが最後、永遠に値を変更できない、と説明しました。言い換えれば、文字列の内容を変更しようと思ったら新しい String型インスタンスが生成されます。ということは、文字列を段階的に作成すると、途中で無駄にたくさんのインスタンスが生成されてしまいます。繰り返し構文を使用する例として、サンプルプログラムを見ていきましょう。
ソースコードは以下の通り。
I201/I201.java
/** * abを 20回繰り返した文字列インスタンスを作成し、表示します。 */ public class I201 { /** * メインメソッド。 * @param args 引数 */ public static void main(String[] args) { String s = ""; for(int i = 0; i < 20; i ++) { s += "ab"; } System.out.println(s); } }
実行結果は以下の通り。
abababababababababababababababababababab
確かに、思うような文字列は生成されています。ところが、Javaのメモリ空間では以下のイメージのようにたくさんの String型インスタンスが生成されています。繰り返しの回数と同じ数だけ、newが実行されているということになります。
インスタンスの生成という処理は負担が大きいと言われます。今回はまだ繰り返しの回数が少なかったから良かったものの、この繰り返しの回数が増えていったら、重たいプログラムになってしまうかもしれません(なお、今時の Javaコンパイラはこのあたりを考慮しているため、気にしなくても問題ないようです)。
Javaでは、内容を変更できる文字列を管理するためのクラスとしてStringBuilderクラスが用意されています。先のプログラムと同じ動作をするプログラムを、StringBuilderクラスを用いて実現してみます。
ソースコードは以下の通り。
I202/I202.java
/** * abを 20回繰り返した文字列インスタンスを作成し、表示します。 * StringBuilderを使用します。 */ public class I202 { /** * メインメソッド。 * @param args 引数 */ public static void main(String[] args) { StringBuilder s = new StringBuilder(); for(int i = 0; i < 20; i ++) { s.append("ab"); } // StringBuilderインスタンスから Stringインスタンスを生成 String t = s.toString(); System.out.println(t); } }
実行結果は以下の通り。
abababababababababababababababababababab
実行結果は変わりませんが、イメージにすると大きな違いが分かると思います。
見ての通り、StringBuilder型インスタンスは 1つだけ。その内容が変更されていることが分かります。このプログラムの場合、繰り返しの回数がどれだけ多くなろうとも、StringBuilder型インスタンスが 1個、String型インスタンスが 2個の合計 3個のインスタンスしか作られないことが分かります。
Java SE 7(Java 1.7)の StringBuilderクラスの説明書(API)を掲示しておきます→StringBuilderクラス。
たくさんのインスタンスメソッドを利用することができます。その中でも特によく使うだろうと思われるものを以下にピックアップしました。
どちらのメソッドも、先ほどのソースコード内に登場していますね。
文字列を使用する場合には、基本的には Stringを使用して問題ありません。ほとんどの場合は、それで大丈夫です。
ただ、繰り返し構文などで文字列を連結していく場合などにおいて、あまりにも無駄なインスタンスが生成される場合には、StringBuilderの使用を考えてみても良いかもしれません。なお、StringBuilderと似たクラスに StringBufferというものがあります。StringBufferクラスのほうが歴史が古いですが、ほとんどは StringBuilderのほうがより適切です。ただし、マルチスレッドという特殊な場合においては、StringBufferを使用しなければならない場合があります。