[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には実装されませんでした。