ここでは、新人エンジニア研修向けにNetBeansのデバッガの使い方を説明します。
バクを取るためにはソースコードをトレースする必要があります。
トレースをするためには、おおむね3つの方法があります。
- 紙とペンを使って静的に解析する
- 変数の内容をSystem.outしながら進める。
- デバッガを使う。
しかし、1の方法は時間がかかる上に不正確です。
2の方法も正確ですが時間がかかる事には違いがありません。
そこで、ここでは効率的にバグを発見するためにデバッガを使う方法をご紹介します。
1.Netbeansのデバッグ機能
例えば、以下のようなプログラムがあったとします。
パッケージは講師の指示に従って作成ください。
かつて10歳だったyuseiが20年たって30歳になり、それから1年が過ぎ、名前もhouseiに変わったという悲しいプログラムです。(こじつけです)
<ソースコード>
ところがこのプログラムを実行したところ、以下のように年齢が1021歳となってしまいました。
<アウトプット例>
My name was yusei and I was 10
Now, My name is housei and I'm 1021
そこで原因究明のためにデバッグするというストーリーです。
まず、デバッグをするにはいったんプログラムを停止させる場所であるブレイクポイントを設定します。
ブレイクポイントを設定していないと、プログラムが最後まで実行されてしまいます。
本来はブレイクポイントは“怪しい行”に設定しますが、説明の都合で、今回は下図3.1のようにメインメソッドの最初と最後の行にブレイクポイントを設定します。
ブレイクポイントは行番号の上をクリックすることで設定できます。
行番号をクリックしてマークと該当行がピンクになればブレイクポイントの設定はOKです。この行の前でプログラムの実行を一旦停止することができます。
次に、「Ctrl+Shift+F5」キーを押すことでファイルをデバッグすることができます。
下図3.2のようにブレークポイントを設定した行が緑になりました。
今からこの行を実行するという意味です。
「F8」キーを押すとそのたびに緑の行が一行ずつ下に動いていきます。
これが、ステップ・オーバーという操作で、恐らく最も多用します。
下部に下図3.3の変数のタブがあります。
(表示されていない場合は、ウィンドウ>デバッグ>変数 を選択します)
ここでは、変数の値を見ることができます。
また、変数の値を直接変更して実行結果を変えることもできますので、試してみてください。
この機能は例えばランダムなテストデータを扱う場合にもデータを固定値に変えられるため便利です。
最後までステップ・オーバーで進めてみましょう。
プログラムの終わりに到達するとデバッグモードは終了します。
また、「F5」キーを押すと続行という操作で次のブレイクポイントまで処理をスキップします。次のブレイクポイントがなければデバックモードを終了します。
任意の場所で終了させるには、「デバッグ>デバッガ・セッションを終了」を選択します。
逆にデバッカセッションを終わらせないと、いつまでたってもデバッグモードのままで無駄に資源を消費してしまいます。
デバックが終わったら忘れずにブレイクポイントを削除しましょう。行番号のピンクのマークをクリックします。
今回は、単純にJavaの演算子が左結合なため、次々と文字列として結合されてしまっていたのでした。
(age + elapsedYears)
と()を使って足し算の優先順位を上げれば解決する問題でした。
このように変数の値を一行ずつ追うことのできるデバッガはバグを見つけるうえで重宝します。
次に、ステップ・インとステップ・アウトを試してみましょう。
まずは、ステップ・インです。
もう一度、「Ctrl+Shift+F5」キーを押してデバッガをスタートさせます。
ステップインのショートカットキーは「F7」です。
これはどのように使うのでしょうか?
先ほどのソースを同じようにデバッグしてみましょう。
同じようにデバッグ実行をするのですが、今度はF8ではなく、F7を使います。
そうすると、8行目のSystem.out.println()のところで別のJavaファイルに行ってしまいました。
行き先はJavaのソースコード(PrintStreamクラス)ですね。
このようにメソッドの中身に入り込むのがステップ・インです。
このままF7を押し続けるとどこまでもメソッドの中に入り込み続けます。
多分、JavaのAPIの中にバグはないと思います。
そこで、メソッドから脱出するには、ステップ・アウトを使います。
ショートカットキーは「Ctrl+F7」です。
どうでしょうか?
元に戻れましたでしょうか?
このステップ・インはどのようなときに使うのでしょうか?
これは、自作のクラスやメソッドに入り込んでバグを探すのに使います。
先ほどのソースを以下のように書き換えてみます。
1つ年を取るという操作をgetOlderというメソッドとして外部に切り出したわけです。
今度は、以下の箇所にブレイクポイントを設定してみます。
elapsedYears = getOlder(age);
もう一度、「Ctrl+Shift+F5」キーを押してデバッガを走らせます。
ステップインのショートカットキーは「F7」でした。
今度はステップ・インで実行するとメソッドの中に入り込みます。
その後は呼び出のメインメソッドに戻ってきます。
このように自作メソッドや自作クラスの中に入り込んで動きを見たい時にステップ・インを使います。
次に例外が発生したときのデバッガの挙動も確認しておきます。
先ほどのソースをすこし修正して、意図的に例外を起こす目的で17行目のgetOlderメソッドの中で0による除算をしてみます。
ステップ・オーバーで一行ずつ処理を進めるとどうなるでしょうか?
今回は、getOlderメソッドを呼び出したところでArithmeticExceptionクラスに飛ばされてしまいました。
このようにどこまで実行されていて、どこで処理が落ちるのかを特定するためにもデバッガを使うことができます。
2.JSPをデバッグする
JSPも同様にデバッグが可能です。
以下のソースコードでまったく同じようにしてみてください。
ブラウザとソースコードの両方を見比べないといけないのが煩雑ではありますが。
これを見るとブラウザがHTML(とJSP)をどのように解析して表示しているのかが分かり興味深いですね。
なお、JSP/サーブレットの場合は、デバッガ・セッションを終了(Shift+F5)を選んで終了させないとデバッグが終わりません。
デバッグが終わらないのは、JSP(その正体はサーブレット)は最初の起動時に生成された1個のインスタンスですべてのリクエストを処理するためです。
次のリクエストを待っている状態で止まっているからです。
3.サーブレットをデバッグする
もちろんサーブレットもデバッグすることができます。
doGetメソッドがあればファイルをデバッグ(Ctrl+Shift+F5)が使えます。
ただし、フォームからの入力値を受け取る場合には、下図3.4のようにリクエスト・パラメータを追加するなどの工夫が必要です。
そうしないとNullPointerExceptionが発生してそこで処理が終わってしまいます。
あるいは、プロジェクトをデバッグ(Ctrl+F5)を選択するのが本来かもしれません。
これは、プロジェクト全体をデバッグするという意味です。
そうすれば、最初から操作の順を追ってデバッグすることができます。
ただし、index.htmlやindex.jpsなどのウェルカムページが作成してあることが前提になります。
デバッグを始めてから怪しいところが出てきたときには、「カーソルまで実行」を使えば、一気にそこまで動作を飛ばすことができます。
カーソルを動的なブレークポイントとして使う方法です。
4.デバッガのまとめ
まとめとして、デバッグ関連のボタンとショートカットキーを一覧にしておきますので参考にしてください。
左から順番に
①デバッガ・セッションを終了(Shift+F5)
②一時停止
③続行(F5) ※次のブレークポイントに進む
④ステップ・オーバー(F8)
⑤式をステップ・オーバー(Shift+F8)
⑥ステップ・イン(F7)
⑦ステップ・アウト(Ctrl+F7)
⑧カーソルまで実行(F4)
です。
以上。