Stringは文字列を扱いますが、インスタンス内の文字列を操作(文字列の追加や削除)することができません。
文字列を操作する際には、StringBufferやStringBuiderを利用します。このページではStringBufferをベースに説明します。StringBufferとStringBuiderの違いはページの最後に説明します。
もくじ
Stringは固定の文字列を扱う
Stringは固定の文字列を扱うため、文字列の変更には向きません。例えば、strという変数内に文字を保存した場合、文字列連結を利用して別の文字列を追加した場合、変数名は同じでもインスタンスは既に別となっています。
1 2 |
String str = "A"; str += "B"; //別のインスタンスが生成される |
つまり、文字列の変更をするたびに、新しくインスタンスを生成することになります。
以下のプログラムでは、数値や文字列の変数を宣言しています。次に、intでもStringでも+=でデータの複合代入(加算+代入、文字列連結+代入)を行っています。
int型の変数は値を加算しながら代入を行うだけですが、String型の変数は+=を利用(文字列を編集)するたびに、別インスタンスが生成されて代入されています。
1 2 3 4 5 6 7 8 |
int a = 10; a += 10; a += 10; String str = "a"; str += "b"; str += "c"; str += "d"; |
StringBufferは可変文字列を扱う
Stringは別の文字列を扱うたびに、内部では別インスタンスを利用してしまいます。それでは効率が悪いため、文字列を変更することが想定される場合はStringBuffer(もしくはStringBuilder)というクラスを利用します。
StringBufferでは文字列が変更されることを前提として様々なメソッドも用意されています。
(下のリンクはオラクル公式APIへのリンクです)
StringBufferのインスタンスを生成する
StringBufferはコンストラクタがオーバーロードされており、引数の形がいくつかありますが、代表的な2つのコンストラクタを紹介します。
StringBufferの引数なしコンストラクタ | |
---|---|
引数なし | StringBuffer インスタンス変数名 = new StringBuffer() ; |
記述例 | StringBuffer sb = new StringBuffer() ; |
StringBufferの引数ありコンストラクタ | |
引数あり | StringBuffer インスタンス変数名 = new StringBuffer(文字列) ; |
記述例 | StringBuffer sb = new StringBuffer(“java”) ; |
引数なしのコンストラクタ利用時は、内部に文字列を持っていないインスタンスを生成します。引数あり(文字列)のコンストラクタ利用時は、引数の文字列を内部に持つインスタンスを生成します。
StringBufferの代表的なメソッド
StringBuiderには可変文字列を扱うための様々なメソッドが用意されています。具体的には、文字列を挿入、削除、編集などです。他にも、Stringと同様のメソッドやStringに変換するためのメソッドも用意されています。
メソッド名 | 戻り値の型 | 引数 | 処理内容 |
---|---|---|---|
append | StringBuffer | String str | StringBuffer内の文字列の末尾に、引数に指定された文字列を追加する。 |
delete | StringBuffer | int start, int end |
第一引数から第二引数までの文字列を削除する。 「あいうえおかきくけこ」という文字列(「」は含めない)の”かき”を削除する場合は、5,7となる。 |
insert | StringBuffer | int offset, String str |
第一引数で指定された場所(インデックス)に、第二引数の文字列を挿入する。 |
length | int | なし | 文字数を戻り値として返す。 |
substring | String | int start, int end |
第一引数の数値から第二引数の数値までの文字列を切り取って、String型の戻り値として返す。 |
toString | String | なし | StringBuffer内の文字列をString型として返す。 |
StringBufferのメソッド サンプルプログラム
以下のプログラムを「Number45.java」という名前でWorkフォルダ内に保存します。
保存が完了したら、コマンドプロンプトを起動し、Number45.javaをコンパイルしてみましょう。※プログラムが長いため、必要に応じてコピペで確認してください
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
class Number45{ public static void main(String[] args){ //引数ありのコンストラクタをでインスタンス生成 StringBuffer sb = new StringBuffer("Java"); /* append()メソッド インスタンス変数.append(文字列) 末尾に文字列を追加する。 */ System.out.println("[append()メソッド]"); System.out.println(sb.append("programming")); /* delete()メソッド インスタンス変数.delete(開始インデックス,終了インデックス) 開始インデックスから終了インデックス-1までの文字列を削除する。 第二引数の数値は-1までのインデックスとなるため、以下の例は「ming」が削除される */ System.out.println("[delte()メソッド]"); System.out.println(sb.delete(11,15)); /* insert()メソッド インスタンス変数.insert(インデックス,文字列) 第一引数で指定されたインデックスに、第二引数の文字列を挿入する。 1文字目と2文字目の間はインデックスが1になる為、下記の例ではapの間に空白が挿入される。 */ System.out.println("[insert()メソッド]"); System.out.println(sb.insert(4," ")); /* length()メソッド インスタンス変数.length() 文字数を返す。 */ System.out.println("[length()メソッド]"); System.out.println(sb.length()); /* substring()メソッド インスタンス変数.substring(インデックス) 内部にある文字列の中からインデックスから最終文字列まで切り取ってStringとして返す。 インスタンス変数.substring(開始インデックス,終了インデックス) 引数が2つの場合は開始インデックスから 終了インデックスまでの文字列を切り取ってStringとして返す。 ※内部の文字列は変更されない */ System.out.println("[substring()メソッド]"); System.out.println(sb.substring(5)); System.out.println(sb.substring(0,4)); /* toString()メソッド インスタンス変数.toString() 内部にある文字列をString型で返す。 */ System.out.println("[toString()メソッド]"); String str = sb.toString(); System.out.println(str); } } |
実行例
C:\work>javac Number45.java
C:\work>java Number45
[append()メソッド]
Javaprogramming
[delte()メソッド]
Javaprogram
[insert()メソッド]
Java program
[length()メソッド]
12
[substring()メソッド]
program
Java
[toString()メソッド]
Java program
StringとStringBufferの注意点
StringもStringBufferも「文字列を扱う」という部分では同じ役割を持つクラスです。
しかし、StringとStringBufferは型が違う為、単純に文字列を比較することはできません。例えば、以下のようなプログラムを記述するとエラーおよびfalseという結果になります。
1 2 3 4 5 6 7 8 |
String str = "abc"; StringBuffer sb = new StringBuffer("abc"); //以下のプログラムは型が違うため、コンパイルエラー System.out.println(sb == str); //以下は文字列ではなくインスタンスの比較となり、falseとなる System.out.println(sb.equals(str)); |
もし、StringBuffer内の文字列とStringの文字列を比較する際には以下のように比較しましょう。
1 2 3 4 5 |
String str = "abc"; StringBuffer sb = new StringBuffer("abc"); //StringBuffer内の文字列をString型で取得して比較 System.out.println(str.equals(sb.toString())); |
上記プログラムでは、String型(str)のequals()メソッドで文字列同士を比較します。StringBufferのインスタンスは利用できないため、StringBufferのtoString()メソッドで文字列同士を比較しています。(誤りの例:str.equals(sb)
補足1 delete()メソッドのインデックス
substring()メソッドのインデックスは以下のようにイメージすると分かりやすいかもしれません。
例えば、mingという部分を取得する場合は「delete(11,15)」と指定します。イメージは以下のようになります。
また、Javaという部分を取得する場合は「delete(0,4)」と指定します。イメージは以下のようになります。
補足2 StringBufferとStringBuiderの違い
公式のAPIドキュメントにも掲載されていますが、StringBufferはスレッドセーフですが、StringBuilderはスレッドセーフではありません。
簡単に解説すると、スレッドセーフとはスレッドというプログラムを利用する際に安全にオブジェクトを利用できるかどうかというものです。
※スレッドについては別ページで解説します
基本的には、スレッドを利用していないプログラムではスレッドセーフでなくても構わないため、どちらのクラスを利用しても構いません。
しかし、StringBuilderのAPIドキュメントには「このクラスは、ほとんどの実装で高速に実行されるので、可能な場合は、StringBufferよりも優先して使用することをお薦めします。」と記述されており、少しでも高速でプログラムを実行させたい場合はStringBuilderにするとよいでしょう。
また、スレッド内で可変文字列を利用する場合は、安全にオブジェクトが利用できるStringBufferが推奨されています。
補足3 戻り値がStringBufferのメソッド
delete()やappend()などのメソッドは、戻り値がvoidではなく、StringBufferとなっています。その戻り値を利用して、出力を行ったり別の変数に代入することも可能です。
StringBufferのインスタンスをSysout()に利用すると内部の文字列が表示されます。
1 2 3 |
//戻り値がStringBufferなので出力が可能 System.out.println(sb.delete(11,15)); System.out.println(sb.insert(4," ")); |
しかし、注意も必要です。戻り値がStringBufferのインスタンスですが、新しくインスタンスを生成しているわけではありません。以下のようなプログラムでは片方のインスタンスを変更したつもりでも両方のインスタンスが変更されます。
1 2 3 4 5 |
StringBuffer sb2 = new StringBuffer("Javaru"); StringBuffer sb3 = sb2.delete(4,6); //sb2のインスタンスとsb3のインスタンスは同一インスタンス sb3.append("プログラミング"); System.out.println(sb2); System.out.println(sb3); |
StringBuffer sb3 = sb2.delete(4,6);
上記の部分は、delete()の戻り値であるインスタンスはsb2自身(のインスタンス)となります。つまり、sb2とsb3は同一インスタンスとなります。
sb3.append(“プログラミング”);
では、sb3だけ追加しているように見えますが、sb2も同一インスタンスの為、出力するとsb2も同じように文字列が追加されています。
StringBuffer 復習問題
- 以下のプログラムをコンパイルおよび実行するとどのような結果となるか選んでください。
12StringBuffer sb = new StringBuffer("test");System.out.println(sb == "test"); - 解答群
- コンパイルエラー
- 実行時エラー
- true
- false
- StringBufferの文字列末尾に、文字列を追加する際のメソッド名を選んでください。
- 解答群
- delete
- append
- create
- indexOf
- 下記プログラムでsbインスタンス内から”def”を削除するプログラムを選んでください。
1StringBuffer sb = new StringBuffer("abcdefg"); - 解答群
- sb.delete(4,6)
- sb.delete(3,5)
- sb.delete(3,6)
- sb.delete(4,5)
- 以下のプログラムをコンパイルおよび実行するとどのような結果となるか選んでください。
12StringBuffer sb4 = new StringBuffer("abc");System.out.println(sb4.equals("abc")); - 解答群
- コンパイルエラー
- 実行時エラー
- true
- false
- お疲れ様でした。
まとめ
- StringBufferは可変文字列を扱う
- append()やdelete()で文字列を変更できる
- Stringの文字列と文字列比較する際は注意
- StringBufferが戻り値の場合は自身のインスタンスを返す