Javaシステムのトラブル事例を基に,設計やソースコードのポイントを解説する。便利な開発方法を用いると,タイプミスをコンパイラでチェックできないケースがある。その結果,文字列をキーにする個所や型変換で実行時に異常終了となる。

 皆さんはJavaを使ったことがあるでしょうか。筆者はシステム開発においてJavaを使うことが多く,約10年の経験があります。以前は処理性能や日本語の問題が取りざたされていましたが,最近はそういった問題はほとんど聞かなくなりました。とはいえ,Javaシステムのトラブルが無くなったわけではありません。

 本特集では,最近経験したり見聞きしたりしたJavaシステムのトラブルを取り上げます。トラブルの原因を明らかにするだけでなく,その代替案や解決策についても解説します。Javaシステムを題材にしていますが,言語は違ってもトラブルの本質には共通する点がありますので,Javaを使わない方にもぜひ読んでほしいと思います。

 今回は,システム・テストになって異常終了するようになったアプリケーションです。まずは,トラブルの症状から説明しましょう。

トラブルの症状と原因

[症状]
 システム・テストに入ってから,アプリケーションのパフォーマンスが悪く,突然異常終了するようになりました。ログを調べると,次のことが確認できました。

問題1:「NullPointerException」が発生して異常終了している

問題2:「ClassCastException」が発生して異常終了している

問題3:頻繁にガベージ・コレクションが発生し,「OutOfMemoryError」で異常終了している

 システムの概要を説明します。このシステムは,PCベースの組み込み機器上で動作する,スタンドアローン・タイプのJavaシステムです。組み込み機器内にはRDBMSがあり,データはそこで管理しています。ログの情報を基に原因を調べていくと,三つの問題点ともDBアクセス(DAO:Database Access Object)部分に関連していることが分かりました。

 このシステムのアプリケーションはDAOを介してDBにアクセスしています(図1List1List2)。DBとのコネクションやトランザクションはDAOで制御しており,アプリケーションからは隠蔽されています。DAOでは,「HashMap」というクラスでRDBMSのデータをメモリー上に展開しています。HashMapではRDBMSの列名とその値を対で読み込むので,手っ取り早くプログラミングする方法としてしばしば用いられます。 RDBMSの1行が一つのHashMapに展開され,RDBMS内の行数分,HashMapのデータがあり,それらをまとめるために「ArrayList」というクラスが使われています。

図1●システム概要
図1●システム概要
[画像のクリックで拡大表示]
static List getResult(ResultSet rs) throws SQLException {
 List ret = new ArrayList();
 while (rs.next()) {
  ResultSetMetaData md = rs.getMetaData();
  Map row = new HashMap();
  for (int i = 1; i <= md.getColumnCount(); ++i) {
   row.put(md.getColumnName(i), rs.getObject(i));
  }
  ret.add(row);
 }
 return ret;
}
List1●DAOのコード
List result = dao.query();
for (Iterator z = result.iterator(); z.hasNext();) {
 Map row = (Map)z.next();
 Integer itemId = (Integer)row.get("itemid");
 String itemName = (String)row.get("item_name");
}
List2●アプリケーションのコード

 アプリケーションはDBのデータを参照するときDAOを介することになりますが,そのデータ形式はList構造で,Listの中身がHashMapになります。

 ちなみに,トラブルが発生するようになったのはシステム・テストなので,ソースコードのコンパイル・エラーはつぶされており,アプリケーションは実行できる状態になっていました。