JavaとScalaのString/StringBuilder/StringBuffer使い分け事情

Scala 3 (Dotty 0.24.0-RC1) 2.13.3 2.12.12
最終更新:2020年7月30日

[AD] scalapediaでは記事作成ボランティアを募集しています

文字列にはミュータブルなのかイミュータブルなのか、StringBuilderなのかStringBufferなのか、はたまたScalaかJavaか、といった複数の観点があります。
これにより、実際どのように使い分けるべきなのか戸惑っている人も多いと思います。

この記事では、java.lang.Stringscala.collection.mutable.StringBuilderjava.lang.StringBuilderjava.lang.StringBufferの使い分けについて解説します。

使い分け早わかりチャート

ScalaやJavaの文字列クラスは、以下の4種類が存在します。

文字列JavaScala
イミュータブルjava.lang.Stringない
可変長文字列(not synchronized)java.lang.StringBuildermutable.StringBuilder
可変長文字列(synchronized)java.lang.StringBufferない

早速ですが、どの場合に何を使うべきかというのを以下に示します。

これに従って使うべき文字列クラスを選びましょう。

以下ではオマケとして、なぜこのような使い分けをするのかについて解説します。

java.lang.StringBuilder, java.lang.StringBuffer の使い分けについて

java.lang.StringBuffer はもはや使いどころがない

Javaの最初のバージョンから用意されているのがjava.lang.StringBufferです。
同期化(synchronized)されています。

「スレッドセーフを確保したい場面であれば、StringBufferを使う」とJavaのAPI Docsには書かれています。
当初はスレッドセーフに扱える便利なクラスとして誕生したのです。

ただし、これだけでは終わりません。

StringBufferには、同期化されている分だけ遅いという欠点がありました。

そして、さらに残念なことに、後年このsynchronizedを利用した同期化については問題が生じやすいことが明らかになりました。
つまり、スレッドセーフにしたいからといってsynchronizedとすればたちまち解決する、というわけではなかったのです。

最終的に、可変長文字列のスレッドセーフについては注意しながら愚直に実装すべきであるというベストプラクティスが共有されました。

したがってStringBuffersynchronizedとしても意味がないということになり、synchronizedのついていない可変長文字列の実装が求められたというわけです。

java.lang.StringBuilderを使いましょう

これを受けて、Java 5で追加されたのがjava.lang.StringBuilderです。

StringBufferの反省を活かし、synchronizedしない実装となっています。
その分処理が高速化されています。

StringBufferとも互換性があります。

そしてStringBufferはもっぱら後方互換の目的で残されることとなりました。 この結果、二つの可変長文字列が共存しているわけです。

存在しているからといっても、StringBufferを使用する理由はないということがわかると思います。

Scalaではscala.collection.mutable.StringBuilderクラスを使えばよい

Scalaでは、内容を変更可能な文字列を扱うにはscala.collection.mutable.StringBuilderクラスを使いましょう。

scala.collection.mutable.StringBuilderは内部実装がjava.lang.StringBuilderです。

scala.collection.mutable.StringBuilderjava.lang.StringBuilderと機能的に互換性があるうえ、さらにScalaで使いやすいように修正されています。

そして、もはやStringBufferは必要とされていないので、これに対応する scala.collection.mutable.StringBuffer のようなものはScalaには実装されませんでした。

サイト内検索


カテゴリ「文字列処理」の記事

文字列をエスケープしたり復元したりする方法(Apache Commons Text) JavaとScalaのString/StringBuilder/StringBuffer使い分け事情 文字列を分割する方法(split・splitAt・linesIterator・linesWithSeparatorsメソッド) trimメソッドで文字列の前後の空白を除去する 文字列が一致するか比較する方法/大文字・小文字を区別せずに比較する方法 特定の文字の文字コード(コード・ポイント)を取得する replaceメソッドなど、文字列を置換する方法を紹介 文字列の先頭や末尾を、取得したり切り落としたりする方法 containsメソッドでStringに特定の文字列が含まれるか調べる方法 数値を文字列に変換する方法 stripメソッドで文字列の前後の全角空白を除去する 文字列を数値に変換するには?to○○メソッドと注意点について 文字列を辞書的に比較する方法/大文字・小文字を区別せずに比較する方法 文字列が特定の文字列で始まるか・終わるかを調べる方法 【getBytes&size】文字列のバイト長を取得する方法 substringでStringを切り取り、部分文字列を抽出する方法 StringOpsとWrappedStringの違いは? 文字列を連結するには?+演算子やString interpolationの使い方 文字列の大文字へ・小文字へ変換する方法 文字列を逆順にする方法 文字列の文字コード(文字セット)を変換する方法 文字列の長さを取得する方法:lengthとcodePointCountの使い分け 文字列をURLエンコード・デコードする方法 文字列が正規表現に合致するか調べる方法 この文字の位置はどこ?文字列のインデックスを取得する方法 文字列をバイト列に、またはバイト列を文字列に変換する方法

カテゴリ「文字列処理」の記事

文字列をエスケープしたり復元したりする方法(Apache Commons Text) JavaとScalaのString/StringBuilder/StringBuffer使い分け事情 文字列を分割する方法(split・splitAt・linesIterator・linesWithSeparatorsメソッド) trimメソッドで文字列の前後の空白を除去する 文字列が一致するか比較する方法/大文字・小文字を区別せずに比較する方法 特定の文字の文字コード(コード・ポイント)を取得する replaceメソッドなど、文字列を置換する方法を紹介 文字列の先頭や末尾を、取得したり切り落としたりする方法 containsメソッドでStringに特定の文字列が含まれるか調べる方法 数値を文字列に変換する方法 stripメソッドで文字列の前後の全角空白を除去する 文字列を数値に変換するには?to○○メソッドと注意点について 文字列を辞書的に比較する方法/大文字・小文字を区別せずに比較する方法 文字列が特定の文字列で始まるか・終わるかを調べる方法 【getBytes&size】文字列のバイト長を取得する方法 substringでStringを切り取り、部分文字列を抽出する方法 StringOpsとWrappedStringの違いは? 文字列を連結するには?+演算子やString interpolationの使い方 文字列の大文字へ・小文字へ変換する方法 文字列を逆順にする方法 文字列の文字コード(文字セット)を変換する方法 文字列の長さを取得する方法:lengthとcodePointCountの使い分け 文字列をURLエンコード・デコードする方法 文字列が正規表現に合致するか調べる方法 この文字の位置はどこ?文字列のインデックスを取得する方法 文字列をバイト列に、またはバイト列を文字列に変換する方法