FrontPage  ページ一覧  検索  更新履歴  ログイン

StringBufferをStringに変換する。あなたなら、どっち?!

まえがき

StringBufferをStringに変換する際の書き方について日記に書いたところ、思ったよりも多くの反応をいただき、大変参考になりました。サイトをまたいだ反応は追いかけづらいので、自分なりにまとめてみます。反応のすべてを網羅しているわけではありませんが、反応してくださった皆様ありがとうございました。

(「ですます調」終了)

想定バージョンについて

なお何点か実装について言及していますが、想定するJ2SDKのバージョンは、1.4.2_03(Sun)です。

1.5(Tiger)での注意

実装が変わっているらしい……:

StringBufferをStringに変換する。あなたなら、どっち?!

結局のところ、StringBuffer(変数名bufとする)があるとして、これをString型に変換するための選択肢は3つ(どっち、じゃ無い!!):

  1. String.valueOf(buf)
  2. buf.toString()
  3. new String(buf) (nekopさんの指摘)

どれを選ぶかの基準は、Stringへの変換時にbufがnullであった場合に取るべき措置による。

A. NullPointerExceptionが発生してほしい/発生する可能性がまずない

「発生する可能性がまずない」というのはStringBufferメソッドローカルなものとして宣言した場合が代表的。

  • buf.toString()またはnew String(buf)。両者の違いは後述
  • NullPointerExceptionの発生がどうするかはコンテキストによる
    • (普通バグだわな)

new String(buf) だと、bufがnullの場合の戻り値は文字列"null"なので、例外は発生しない(後述)

B. NullPointerExceptionが発生してもらっては困る

  • 迷わずString.valueOf(buf)。戻り値はとにかく必ずString
  • bufがnullだった場合は、文字列"null"が得られる

想定されるコンテキストとして「ログの書き出し」(だーまんの日記)が挙げられている。他にもあるかも。

参考: 実装

(buf == null) ? "null" : buf.toString();

つまり、bufがnullの場合の戻り値は文字列"null"。例外は発生しない。

じゃあ、buf.toString() と new String(buf)とではどっち?

buf.toString()

  • 実装は new String(this)。つまり、new String(buf)への委譲メソッド
  • new String(buf)に較べて1メソッド分、呼び出しコストがかかる(考慮しないといけないかなぁ?)
  • メッセージ脳っぽい(Not Enough Resource)
  • そうはいっても、toString()はデバッグ用だよな。
  • JDK1.4からはCharSequenceインタフェースがあるので、toString()でも良い。

new String(buf)

  • これはbufの文字列表現の取得ではない。String型への変換なのだ。
  • パフォーマンス的にはベスト」(manholeのおきらくごくらく日記)
    • そうはいっても、1メソッド分
  • 禁じ手である new String("I'm dummy"); と紛らわしいかも?(んなこたぁないか)

教訓

今回の個人的な教訓:

  • Javadoc読め
  • src.zip使え
  • JavaHouse読め (nekopさん)
    • このスレのまとめが欲しい……。

これではJava技術者を名乗るのも憚られますな。

思考のたれ流し

以下に関連して考えたことなどを記述しておく。

StringBufferで確保した配列の共有

両者の間に(というかString.valueOf(buf)とも)違いはない。というのは、StringBuffer#toString()はStringのコンストラクタへの委譲メソッドであり、配列の共有処理自体はnew String(StringBuffer)で行われているからだ。

ただし、指摘された通り」(Strayy Night)、この記述自体はStringBuffer#toString()のJavadocにある。

java.lang.CharSequenceインタフェース

J2SDK1.4からString, StringBuffer, java.nio.CharBufferを透過的に扱えるようにするためのインターフェースとしてjava.lang.CharSequence導入されている。

目的はjava.util.regexパッケージでこれらを透過的に扱うためのようだが、収録パッケージがjava.langなので、基本的なデータ型としてCharSequenceを利用するというテもなくはない(1.4以降に限る)。

インタフェース: java.util.regex パッケージのメソッドに引数として渡せるオブジェクトによって実装されるインタフェース。 String、StringBuffer、および java.nio.CharBuffer クラスがこのインタフェースを実装する

文字列表現と文字列型への変換(Rubyとの比較)

この項は個人的な思いつき。たとえばRubyだと、Object#to_s と Object#to_str がある。

Object#to_s

  • オブジェクトの文字列表現を返す
  • print や sprintf は文字列以外のオブジェクトが引数に渡された場合このメソッドを使って文字列に変換する

これはJavaのObject.toString()相当だな、と。Javadocにも「通常、toString メソッドはこのオブジェクトを「テキストで表現する」文字列を返します。この結果は、人間が読める簡潔で有益な情報であるべき」とある。

Object#to_str

  • オブジェクトの文字列への暗黙の変換が必要なときに呼ばれます。

JavaのObjectにはこれがない。まあ、文字列型にこだわる必要がJavaには無いし、別の言語だからいいんだけど、Javaでも「文字列表現」と「文字列型」の区別があってもいいのに、と思う。オチは無し。

コメント

なにかありましたらお気軽に

  • 2004-02-21 (土) 17:48:45 nekop : JDK1.3までは、CharSequenceインタフェースがありませんでした。今ではCharSequenceがあるのでtoString()でも良いのですが、無かったころは、主にデバッグ文生成のために使われていたtoString()を使用することには抵抗がありました。なので、StringBufferを内部データを表現するStringの生成を明示するという意味で、new String()を使っていたわけです。
  • 2004-02-21 (土) 17:50:31 nekop : 記事中にCharSequenceのtypoが2箇所あるので修正お願いします。ceがseになっています。
  • 2004-02-21 (土) 17:52:46 nekop : あと、メソッド呼び出し一つしか違わないものに対しパフォーマンスをどうこう言うのはちょっとアレです。
  • 2004-02-21 (土) 18:03:26 nekop : あとは http://java-house.jp/ml/archive/j-h-b/012934.html#body このへんをどうぞ。
  • 2004-02-25 (水) 18:32:32 かくたに : 今頃ですが修正しましたー。JavaHouseのログ読んだら、全面的に書き直しの必要ありですね、これ……。
  • 2004-03-16 (火) 12:21:32 manhole : パフォーマンス云々はnekopさんに同意です。で、JavaHouseのログ見たら考えが変わりました。深い…。
  • 2004-03-16 (火) 15:50:56 Skirnir : 興味深く拝見しました。また、java-houseの議論も読んだのですが、CharSequenceインタフェースが導入された現状を踏まえて風間さんにぜひ意見を聞いてみたくなりました。
更新日時:2007/06/05 14:11:29
キーワード:
参照:[FrontPage]