torutkのブログスマートフォン用の表示で見るtorutkのブログソフトウェア・エンジニアのブログ2019-09-09ResultSetがStreamになったら嬉しいかもはじめにJDBCでデータベース検索のプログラムを書いていると、テーブル毎に似たような、そしてちょっとずつ異なるコードを書くことになります。異なる部分は、カラム名、データ型、そして取り出したバラバラの値をJavaのデータクラス(ドメインクラスであったり、DTOであったり)に詰める処理です。典型的には以下のようなプログラミングになるかと思います。}}JDBCでは、SQL検索文を発行した結果をResultSetで取得します。ResultSetはnext()でカーソルを進めて、getXXメソッドでカラムの値を取り出す仕様となっています。SQL文、PreparedStatementへのプレースホルダーの値設定、ResultSetからのカラムの取り出し、といった部分はテーブル固有の記載となります。上述のように結構長々と書くことになり、また、同じテーブルでも検索の条件毎にSQL文とプレースホルダー、戻り値が異なるので、別々なメソッドにResultSetのイテレーション処理を記述することになります。ResultSetをStreamにしたら探してみると、ResultSetをjava.util.stream.Streamでラップするというブログ等がいくつか見つかりました。いうライブラリも存在します。インタフェースを使ってResultSetをStreamにするという内容。実際にはjava.util.SpliteratorsクラスのネストクラスAbstractSpliteratorを継承し、ResultSetからオブジェクトへのマッピングは著者の別ライブラリSqlMapperを使っている。Stream処理内(tryAdvanceメソッド内)で発生したSQLExceptionは、ResultSetのnextで生じたものはRuntimeExceptionにラップして投げており、ResultSetから値を取り出す際に生じたものは結果を返すオブジェクトにエラーを格納して戻り値としている。インタフェースを使ってResultSetをStreamにする内容。こちらもAbstractSpliteratorを継承したResultSetSpliteratorクラスを定義し、ReslutSetからオブジェクトへのマッピングは、そのResultSetSpliteratorクラスの抽象メソッドprocessRowをさらに用途に応じてサブクラスで実装するというアプローチ。Stream処理内(tryAdvanceメソッド内)で発生したSQLExceptionはRuntimeExceptionにラップして投げている。AbstractSpliteratorのtryAdvanceを実装した無名クラスを生成し、ResultSetからは固定のRecordクラスにマッピングしている。Recordクラスは、カラム名をキーに、値をObject型で格納するMapをフィールドに保持する。Spliteratorインタフェースを実装したクラスを定義している。ResultSetから任意の型のオブジェクトに変換するFunction(検査例外をスローする独自インタフェース)を受け取り、Stream処理内からSQLExceptionをスローし外側でキャッチできるようにしている。お試し実装AbstractSpliteratorを継承したResultSetSpliteratorを定義し、ResultSetの各行を任意の型のオブジェクトに変換するFunctionを外から渡せるようにします。上述ブログ・書籍の最後の記事にほぼ沿った実装です。E;}使用例ResultSetをStreamにしたら、次のように記述できます。}ここでは、ResultSetからオブジェクトへの変換をラムダ式でインライン記述しています。複数個所で同じラムダ式を記述する必要が生じた場合は、ラムダ式をフィールドに定義して再利用する等ができます。月別アーカイブはてなブログをはじめよう!torutkさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。