Cursorをcloseするタイミング

            先日書いた「<a href="http://blog.tnnsst35.me/2011/12/09/android%E3%81%A7sqlite%E3%82%92%E3%81%A4%E3%81%8B%E3%81%86/">AndroidでSQLiteをつかう</a>」にのせたコード(をベースにしたコード)をコードレビューしてもらった。

いろいろと指摘されたことをメモしておく。

主に改善点があるコード [java] try { Cursor c = db.rawQuery(sql, null); boolean isEof = c.moveToFirst(); result += "["; while (isEof) { result += "{"; for (int i = 0;i < c.getColumnCount();i++) { if (i != 0) result += ","; result += "\"" + c.getColumnName(i) + "\":\"" + c.getString(i) + "\""; } result += "}"; isEof = c.moveToNext(); if (isEof) result += ","; } result += "]"; c.close(); } catch (SQLiteException e) { result = "Failed to execute SQL : " + e.getMessage(); } [/java]

改善点 ・JSON文字列を作るにはJSONArrayとJSONObjectを使う。 ・Cursor(に限らず)を閉じるというような処理は、finallyの中でやるのが鉄則。

改善後のコード [java] Cursor c = null; try { c = this.db.rawQuery(sql, null); JSONArray items = new JSONArray(); if (c.moveToFirst()) { do { JSONObject item = new JSONObject(); for (int i = 0;i < c.getColumnCount();i++) { try { item.put(c.getColumnName(i), c.getString(i)); } catch (JSONException e) { e.printStackTrace(); } } items.put(item); } while(c.moveToNext()); } result = items.toString(); } catch (SQLiteException e) { result = "Failed executeSQL SQLite -- " + e.getMessage(); } finally { try { if (c != null) { c.close(); } } catch(SQLiteException e) { e.printStackTrace(); } } [/java]

JSONArrayとJSONObjectはそういうのがあるんだなという感じでOK。

Cursorをcloseするタイミングに関しては「ほぉ」と思った。 僕はここ3年間ずっとPHPをやってきたが、PHPには「finally」は存在しない。なので「finally」の存在をすっかり忘れていた。

[java] try {   例外をスローする可能性のある処理 } catch (例外クラス型 引数名) {   例外処理(例外ハンドラ) } finally {   最後に必ず実行される処理 } [/java]

SQLiteDatabaseも同様のタイミング(finallyの中)でcloseすると間違いはない。 また try ~ catch まみれになるがJavaはそういうものらしいので気にしない。

参考 : カーソルが解放されるタイミング (2)

おわり。