【Java】while (rs.next()) {...でResultSetをDTO→Listにaddする図解
Javaを学習していて「ここ、複雑だな」と感じた部分がありました。
それは、DAOクラス内でDB検索結果の詰まったResultSetをsetterメソッドでDTOに格納した後に、DTO自体をさらにListにaddしていくのをwhileで繰り返す、という処理の部分です。
コードで例を書くとこんな感じ。
これ、初見だと暗号化された文字列の羅列にしか見えなくないですか??
「読む気も起きねぇ・・・!」ってなりませんでした?これをすんなり理解出来たら秀才だと思います。
というわけで、ここの部分を「映像化・言語化」をしながら解説を試みてみます。
一度イメージできるようになれば簡単なことが分かります。
ー もくじ ー
while (rs.next()) {... の話を進める上での前提
まず、今回の例でDTOに保持する情報と、DTOに保持させるデータ元となるデータベーステーブル構成を書いておきます。
また、↓で図示したとおり「DTO=情報を保存しておく箱」くらいのイメージでOKです。
DTOって何!?って考え始めるとドハマりするので今は難しく考えないようにしましょう。
- 今回の例でDTOが持つ情報は以下のとおり。名前(age)と年齢(age)のみ保持します。
- 今回の例で使うデータベースのテーブル構成は以下。
可能な限り簡潔にするためnameカラム(列)とageカラムだけを持つ簡単なテーブルにしています。
最初の行から順番に図解
さっそくコードを見ていきます。
ArrayListをnewする、をイメージする
この一番最初の行を具体的にイメージできるかどうかで、最後まで理解できるかどうかかが決まると言っても過言ではありません。
一番最初の行でDTOListというリスト(ArrayList)をnewしていることが読み取れますね。
これは、いったい何をしているのでしょうか?
今後、Listをnewしているコードを見つけたら以下のように「新しい空っぽの部屋」が作られる映像を想像してください。
実際にはnewされた時点では部屋は1つもない状態なのですが、今回の例題に限り簡単にするため最初から「3つの部屋が作られた」と考えてください。
Listの部屋一つひとつには識別番号として0から始まる連番が割り当てられていることも覚えておきましょう。
後になってこの空っぽの部屋の中にぽんぽん情報の入った箱が詰め込まれていくので、必ず頭の中で映像化してください。
必 ず 、 頭 の 中 で 映 像 化 し て く だ さ い 。
最初の1行目、Listをnewするところまでは良いでしょうか?
次は、2行目以降のSQL文を定義して実行するコード部分です。
rs(ResultSet)にSQL実行結果を格納する
「select *」 で全ての行をデータベースから検索して引っ張りだせ、という意味なので、nameカラムとageカラムで構成される今回のデータベーステーブルの内容がそっくりそのままゴッソリと取り出されます。
そして、rs = ... となっているので「rs」という変数の中にデータベース検索結果がそのまま格納されます。
上図のように、「rs」という黄色い箱の中に検索の結果取り出された内容がまるっと納められたイメージです。
rsってなに?と思った方は、深く考えすぎず「DB検索結果だけが入る箱」というイメージでOKです。
ここまで、以下3行を見てきました。
List<DTO> DTOList = new ArrayList<DTO>();
String sql = "select * from user";
・・・省略・・・
rs = ps.executeQuery();
この時点で出来上がっているモノをもう一度確認します。
- "DTOList" という連続した空部屋
- DB検索結果がまるっと格納された"rs"という名の変数(箱)
この2つが出来上がっています。
DTOListが次に登場するのは最後の方なので忘れずに頭の片隅に置いておきましょう。
次は、いよいよ一番ワケがわからなくなるwhileで繰り返す部分です。
while文でrs.next()以下を繰り返す、のイメージ
rs.next()の場合はずっと繰り返せ、ではまだ意味が分かりませんよね。
では、この「while (rs.next())」をとても丁寧に日本語に翻訳してもらいましょう。
長かったですね。何が何だかさっぱりという方向けにしつこめに表現してみましたが、rs.next()という短い単語にはこんなに長い意味が込められてるといえます。
敢えて一言でまとめるなら、
1行ごとのデータに対して「・・・」部分のコードを実行していき、最後の行の次の行へたどり着いたら終わり
という感じ。
ポイントは、絵で描いたように「矢印のカーソル」が行の横に置いてあって、whileが1周する毎にカーソルが1行下にずれていく映像をイメージすることです。
rs.next()のネクストは文字通り「次」という意味なので「rsの次の行へ移る」と考えればそのまんまですよね。
さて、次からはwhile文の中で実行される上記でボカした「・・・」部分の処理イメージです。
まずは"dto"という空っぽの箱を作るところから。
while文で実行する事① DTOをnewする
while(rs.next()) { の直後で、DTOをnewしていますね。
ここで「話を進める上での前提」で書いたDTOが保持する情報を思い出してください。
名前と年齢を保持するだけの箱でした。まだnewされた(新しく作られた)だけなので、nameとageには実体となる情報は空欄(図では"---"と表現)のままです。
dtoという名前の箱が作られたあとは、while文の中で一番ややこしい部分。
while文で実行する事② dtoにsetする
dto.setName(rs.getString("name"));
dto.setAge(rs.getInt("age"));
パッと見ただけでは何をしてるかさっぱりだと思います。
いきなり理解するのは無理なので、前半と後半に分けて後半から考える、という手段でいきます。
では、まずは後半のrs.getXXXから、
rs.getString("name");
rs.getInt("age");
これらは何を意味するでしょうか?
ポイントは、文字通り読む事です。
- rsの"name"カラムに該当するStringの値を持ってくる(get)という意味。
- rsの"age"カラムに該当するintの値を持ってくる(get)という意味。
イメージ図にするともっと簡単になります。今回の例だと、
- 「"Yuki"というStringをgetする」
- 「"30"というintをgetする」
という意味になります。まだwhileの1周目なので1行目にカーソルが当たっていることを忘れないでください。
dto.setName(rs.getString("name"));
dto.setAge(rs.getInt("age"));
これでは何を意味するか、分かりづらい状態でしたが、
dto.setName("Yuki");
dto.setAge(30);
カッコの中に入るデータの実態はこうであると分かれば、かなり見通しが良くなりました。あとはdtoにsetするだけで良さそうですね。
dtoは、「setしろ!」という指示があったら言われた通り値をセットするだけの簡単な仕事をするんでしたね(話を進める上での前提部分を参照)。
これで、実際の名前と年齢情報を持った箱が誕生しました。
あとは最後に
DTOList.add(dto);
このコードを実行するだけでwhile文の1周目が終わります。
DTOListにdtoをaddする
ここで、一番最初にDTOListがnewされていたことを思い出しましょう。クドいですが、イラストを再掲します。
このDTOListの空っぽの部屋に、データ(dto)が追加(add)されていきます。
DTOList.add(dto);
addされるのは、 1,2行前で名前と年齢情報が格納されたばかりの"dto"という箱です。
DTOList.add(dto); はそのまんま文字通りの意味、ということがよく分かるのではないでしょうか?
これでwhile文の1周目が完了しました。
DTOListの0番目の部屋にdtoが格納されており、そのdtoのなかに名前と年齢情報が格納されている
という状況です。
while文の終了条件は、rs.next()が意味するところの「rsを1行ずつ見ていってデータの格納された行への処理が終わったら」でした。
まだ2行目、3行目にデータが残っているのでwhile文の繰り返し処理は続きます。
while文 2周目, 3周目
2周目は、データ処理の対象がrsの2行目に移るだけで1周目と全く同じ処理が行われます。
dtoに2行目の情報が格納されたところで、
DTOList.add(dto);
が実行され、2周目の処理が終了します。
3周目も全く同じなので、1枚で完結に。
今回は3列しかなかったのでdtoとDTOListの部屋がそれぞれ3つずつできてwhile文が終了しましたが、これはつまり「selectした結果の行数分だけdtoとDTOListの部屋が出来上がる」ということになりますね。
以上、ResultSet をdtoにsetしてそのdtoをDTOListに格納するイメージ図解でした。
nameの値を取り出すコード
while文でrsの内容がdtoにセットされ、そのdtoがDTOListに格納されるところまで説明しました。
最後に「dtoの中身の値を取り出したい場合は?」の疑問を解消します。
以下、0番目の部屋にあるdtoの中のnameの値を取り出す場合。
たとえば、
System.out.print(DTOList.get(0).getName());
とコードを書くとコンソール画面に「Yuki」と表示され、
System.out.print(DTOList.get(2).getName());
とすると「Ken」と表示されます。
while(rs.next()) {... DTOList.add(dto)のまとめ
- DTOListという連続した空部屋が作られる(new ArrayList<DTO>())
---以下、while文に突入--- - DTO dto = new DTO();
... dtoという箱が作られる - rs.getString("name"), rs.getString("age")
... rs(DB検索結果)から"name"カラム、"age"カラムの値を取得する - dto.setName(〜), dto.setAge(〜)
... ③の値をdtoに格納する - DTOList.add(dto);
... ④のdtoを①のDTOListに格納する - ②〜⑤をrsが空の行になるまで繰り返す
長い記事を読んでいただきありがとうございました。
関連記事Javaが難しい?Udemyで学習すべし【おすすめ入門講座1選】