String の連結ネタの続き
以下のコードはどうなるでしょう。こたえは一番下。
String str = null; str += new Object(); System.out.println(str);
http://d.hatena.ne.jp/irof/20110305/p1 の続きっぽい何か。
引っ張りすぎだと思わなくもありませんが、思うところは書いておこうと思います。
その前に質問文が変わっていたので再回答。
- Q2. 文字列の+演算子による連結とStringBuilderを使った連結の違いを説明せよ。
- A2. Stringは不変なので連結した新しいインスタンスが作られる。StringBuilderは可変なので変更される。
Stringは不変ですから、String.concat(String) を使っても連結するごとに新しい String を作ることになります。で、 +演算子 で連結すると、コンパイラが String を StringBuilder に変換して連結してーとかなにやらごちゃごちゃしてます。その結果、String→StringBuilder→String とかするので、 StringBuilder でそのまま連結しちゃうのに比べてちょっと多めにインスタンスが作られる事もあるのです。一概に言えないので、この辺は面倒。正直細かいパフォーマンスなんてどうでもいいんです。
それでタイトルの String の連結、特に +演算子 についてですが…
うらがみさんがこう言ってます(勝手に引用
Java言語仕様は持ってないけれど*1、だいたいそんな感じかなーと。コンパイラの最適化が何をどうするかはコンパイラ次第だし、+演算子のパフォーマンスはコンパイラに依存していると言えます。つまり、今以上に最適化される可能性もあるわけです。今は StringBuilder で書いたほうが高速かもしれないけれど、 StringBuffer の前例*2があるのでどうなるか判ったもんじゃありません。数個レベルの単純な連結においては +演算子 を使った方が良いのかもしれませんし、「String は +演算子 で連結するものだ」と思っても特に問題はない*3と思います。
だって、String って普通そんな連結しないと思うのですよ。業務システムでは大量データを扱う事もあります。だけど膨大なデータを扱う事の多くはデータベースのレコード数とかです。その全件を String で連結するかと言われると、そんな経験ありません。
それに、String として存在しなきゃいけないタイミングは外部との読み書きくらいだよね。1万回連結したらパフォーマンスに差が出た。なるほど、話はわかった。だがその文字列はどうするんだね。私は読みたくないぞ。人に読ませないなら何かに出力するんだろうけど、巨大な String を作って一気に書き出すとかそんなチャレンジしたくない。そんなのやるくらいなら別の方法考えます。そんなわけで +演算子 は十分実用に耐える道具なので、使えるところでは使えば良いと思うのです。
とはいえ、できれば演算子は使いたくない人間だったりします。だって、なんか読みづらい。意図がわかんにくいから。フィールド名が数値っぽかったら怪しさ満載だし。
もっとも、「String で扱う事」が命題ではないでしょう。たまたま扱いやすい(と思っている)型が String ってだけだと思うのです。可変文字列なら StringBuilder の方が私は使いやすいし、読みやすいと思う。結局はどんな事をやりたくて、やどんなコードを読んできて、どんなコードを書くかって話になっちゃうんだと思う。適材適所、持っている中で適切な道具を選ぶのも楽しさの一つだと思うのです。
クイズのこたえ
nulljava.lang.Object@459189e1
凄く普通ですね。普通にコンパイルできて、普通に連結されます。コンパイル出来ないと思うかもしれないし、演算子をメソッド的に考えちゃうと NullPointerException だと思ったりするのかも。String フィールドに対する +演算子 の挙動を何となく想像できるかなーと思います。javap すればおしまいなんだけど、それは言いっこなしで…。
…NullPointerExceptionになる Groovy な方向けのネタはご用意しておりません。