Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Improving performance in Kotlin with string concatenation

2025年10月02日に「Dev.to」が公開したITニュース「Improving performance in Kotlin with string concatenation」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

Kotlinで文字列を`+=`で結合すると、新しいStringが都度作られメモリや処理効率が悪くなる。解決策は`StringBuilder`を使うことだ。`StringBuilder`は効率的に文字列を変更でき、メモリを節約し処理を高速化する。特に大規模な結合で効果的だ。

ITニュース解説

物流会社のAndroidモバイルアプリケーションで発生したパフォーマンス改善の事例から、システム開発における重要な学びを紹介する。このアプリケーションは、作業員が荷物のラベルをスキャンし、荷物の仕分けに必要な情報をシステムへ登録する役割を担っている。特に、ラベルから読み取った文字列やバイトデータを加工し、バックエンドシステムが処理しやすい形式に整えて送る機能は、アプリケーション全体の「心臓部」と言えるほど重要だ。この機能が滞れば、物流プロセス全体が停止してしまうため、どんな小さな改善でも歓迎される状況だった。

ここで取り組まれた改善は、非常に基本的な文字列の連結処理、すなわち「文字列をつなぎ合わせる操作」の効率化である。文字列連結はプログラミングで頻繁に行われる操作だが、そのやり方次第でメモリの消費量や処理時間に大きな問題を引き起こす可能性がある。

具体的にどのような問題があったのかというと、改善前は多くのプログラマーが日常的に使う += 演算子を用いて文字列を連結していた。例えば、以下のようなコードである。

1var result = ""
2val iterations = 1000
3for (i in 0 until iterations) {
4    result += "Item $i "
5}

このコードでは、result という変数に Item 0Item 1 といった文字列が繰り返し追加されている。一見問題なさそうに見えるが、実はここに大きな落とし穴がある。プログラミング言語における文字列(Stringオブジェクト)は「イミュータブル(immutable)」、つまり「一度作成したら内容を変更できない」という特性を持っていることが多い。KotlinのStringもこの特性を持つ。

そのため、result += "Item $i " という処理が行われるたびに、内部では以下のようなことが起きている。まず、現在の result の内容と、新しく追加される Item $i の内容を合わせた、全く新しい文字列がメモリ上に作成される。そして、その新しい文字列が result 変数に代入されるのだ。元の result が保持していた古い文字列は、もう使われないためメモリ上に取り残されるか、後でシステムによって回収される対象となる。

この処理がループ内で1000回繰り返されると、1000回も新しい文字列オブジェクトがメモリ上に生成され、そのたびにメモリが余分に割り当てられることになる。結果として、メモリの使用量が増大し、新しいオブジェクトを生成するコストと、不要になったオブジェクトを回収するコストによって、処理にかかる時間も大幅に増加してしまうのだ。繰り返しの回数や連結する文字列の長さが増えるほど、この問題はさらに深刻になる。

この問題の解決策として採用されたのが、StringBuilderという別の種類のオブジェクトを使用することだった。StringBuilderは、Stringとは異なり「ミュータブル(mutable)」、つまり「内容を変更できる」という特性を持っている。

StringBuilderを使った文字列連結は、以下のように実装できる。KotlinではbuildStringという便利な関数が提供されており、その内部でStringBuilderが利用される。

1val result = buildString {
2    for (i in 0 until iterations) {
3        append("Item $i ")
4    }
5}

StringBuilderを使用した場合、append("Item $i ")という処理が行われるたびに新しい文字列オブジェクトが生成されることはない。代わりに、StringBuilderは内部に確保したメモリ領域を効率的に利用し、そこに直接新しい文字データを追加していく。これにより、繰り返し処理の中で何度も新しいメモリを確保したり、古いオブジェクトを破棄したりする手間が省けるため、メモリの使用量を抑えつつ、はるかに高速に文字列連結処理を実行できるのだ。

実際に、+= 演算子を使った場合とbuildStringStringBuilder)を使った場合の処理時間を比較すると、その効果は歴然だ。1000回の文字列連結処理を計測したところ、+= 演算子を使った場合は21ミリ秒かかったのに対し、buildStringを使った場合は0ミリ秒という結果が出た。この数値が示すように、両者には圧倒的なパフォーマンスの差がある。これはあくまでシンプルな例での計測だが、実際のアプリケーションで扱う文字列がもっと長かったり、連結処理の回数がはるかに多かったりする大規模なシステムでは、この時間差とメモリ消費量の差は文字通り何百倍、何千倍にも膨れ上がる可能性がある。

この事例が教えてくれることは、プロジェクトに大きな影響を与える改善とは、必ずしもアプリケーション全体のアーキテクチャを変更するような大がかりなものである必要はないということだ。今回のように、一見地味に見える文字列連結の方法といった、コードの細部におけるシンプルな改善であっても、それがアプリケーションの「心臓部」となるような重要な機能で適用されれば、ユーザー体験の向上やビジネス価値の創出に計り知れないほどの大きなインパクトをもたらすことがある。システムエンジニアとして、日々のコーディングにおいて、このような細部の効率化やパフォーマンスへの意識を持つことが、非常に重要だと言える。

関連コンテンツ

関連IT用語