再帰の誘い [日記]
とあるWWWアプリケーションで使っているJava実行環境を1.3から5.0に変更しました。
テストも一通り終り、本番環境で動かしてみると、動作が変だ。
なんとなく、例外を投げて途中で止まっているっぽい。今まで動いていたのに。
そこで、怪しそうな場所を
try { ~~ } catch (Exception e) { e.printStackTrace(); }
で囲ってみた。
結果。変らず。スタックトレースの出力も無し。
小一時間程悩んでから、Servletコンテナ(ぶっちゃけTomcat)のログを確認することに(普通は真っ先にコレを確認するべきだ)。
すると、StackOverflowError
が出ている。
あー。
そりゃ、
try { ~~ } catch (Exception e) { e.printStackTrace(); }
じゃ駄目だ。
さて、
StackOverflowError
が出るのは、大抵、再帰呼び出しの終了条件が間違っているのが原因。解りやすい理由でよかった。
でも、今まで動いていたんだけどな、これ。
改めて例外の発生場所を突き止めると、こんな感じ。
public class example { BufferedReader in = new BufferedReader(new FileReader("○○")); public String get() throws IOException { String str = in.readLine(); if (str == null) return ""; return str + get(); } }
ファイルからデータを1行ずつ読んで、連結して返す関数です。
大体3000行くらいのファイルを読ませたら、スタックが溢れました。
テストの時は、小さいファイルを使ってたから問題なかったのか。
Java 1.3の時は同じデータでもちゃんと動いたけど………スタックの総量が多かったのか、関数呼び出し1回で消費するスタックが少ないのか……?。
とにかく、
典型的な再帰の無駄遣いですな、これは。
まぁ、気持ちは解る。
再帰呼び出しを覚えると、とりあえず再帰で実装してみたり、
C++でテンプレートに値が指定できる事とテンプレートの部分特殊化を覚えると、無駄にテンプレートプログラミング(コンパイルタイムプログラミングとも言う)してみたり、
リストの畳み込み演算を覚えると、何でもかんでも畳み込み演算で実現してみたりしますからねぇ……。
今日の一冊 | |
|
コメント 0