[AD] Scalaアプリケーションの開発・保守は合同会社ミルクソフトにお任せください
文字列にはミュータブルなのかイミュータブルなのか、StringBuilderなのかStringBufferなのか、はたまたScalaかJavaか、といった複数の観点があります。
これにより、実際どのように使い分けるべきなのか戸惑っている人も多いと思います。
この記事では、java.lang.String
、scala.collection.mutable.StringBuilder
、java.lang.StringBuilder
とjava.lang.StringBuffer
の使い分けについて解説します。
使い分け早わかりチャート
ScalaやJavaの文字列クラスは、以下の4種類が存在します。
文字列 | Java | Scala |
---|---|---|
イミュータブル | java.lang.String | ない |
可変長文字列(not synchronized) | java.lang.StringBuilder | mutable.StringBuilder |
可変長文字列(synchronized) | java.lang.StringBuffer | ない |
早速ですが、どの場合に何を使うべきかというのを以下に示します。
これに従って使うべき文字列クラスを選びましょう。
- 変更を繰り返す?
- 繰り返さない場合
- →
java.lang.String
を使えばOK
- →
- 繰り返す場合
- → 可変長文字列を使用する。この方が効率的なので。
- 言語は?
- Scalaのコードなら
- Javaのコードなら
- →
java.lang.StringBuilder
を使用するjava.lang.StringBuffer
は、もう使いません
- →
- 言語は?
- → 可変長文字列を使用する。この方が効率的なので。
- 繰り返さない場合
以下ではオマケとして、なぜこのような使い分けをするのかについて解説します。
java.lang.StringBuilder, java.lang.StringBuffer の使い分けについて
java.lang.StringBuffer
はもはや使いどころがない
Javaの最初のバージョンから用意されているのがjava.lang.StringBuffer
です。
同期化(synchronized
)されています。
「スレッドセーフを確保したい場面であれば、StringBuffer
を使う」とJavaのAPI Docsには書かれています。
当初はスレッドセーフに扱える便利なクラスとして誕生したのです。
ただし、これだけでは終わりません。
StringBuffer
には、同期化されている分だけ遅いという欠点がありました。
そして、さらに残念なことに、後年このsynchronized
を利用した同期化については問題が生じやすいことが明らかになりました。
つまり、スレッドセーフにしたいからといってsynchronized
とすればたちまち解決する、というわけではなかったのです。
最終的に、可変長文字列のスレッドセーフについては注意しながら愚直に実装すべきであるというベストプラクティスが共有されました。
したがってStringBuffer
をsynchronized
としても意味がないということになり、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.StringBuilder
はjava.lang.StringBuilder
と機能的に互換性があるうえ、さらにScalaで使いやすいように修正されています。
そして、もはやStringBuffer
は必要とされていないので、これに対応する scala.collection.mutable.StringBuffer のようなものはScalaには実装されませんでした。