倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

Source, Result と close() 処理

Source, Result インターフェースには、リソースを扱うクラスやインターフェースに通常定義されている「リソース解放」メソッド close()*1 が定義されていないため、これらの処理が自動的に行われていると勝手に思い込んでいましたが、どうもそうではないようで()。 以前に書いた SourceResult の記事ではこれらを考慮してませんでしたm(_ _)m

DOM, JDOM, dom4j に関するものは、リソースを解放し忘れても何てことはない(そもそも既にメモリ上に展開されている)ので、まぁ心配はないでしょう。

Stream, SAX, StAX に関するものに対して「リソース解放」が実行されているかどうか調べてみると、結果は下表のようになりました:

入力 自動処理 出力 自動処理
Stream stream InputStream OutputStream ×
Stream Reader/Writer Reader Writer ×
SAX InputSource ContentHandler 不要
StAX stream XMLStreamReader × XMLStreamWriter ×
StAX event XMLEventReader × XMLEventWriter ×

StreamSource, StreamResult に関して、システム ID を表す String オブジェクトやファイルを表す File オブジェクトコンストラクタの引数にして得られたインスタンスに対しては「リソースの解放」が行われているかどうかは調べていませんが、上記の結果から、StreamSource では行われており、StreamResult では行われていないと思われます。

ただし、この結果は Transformer クラスの実装に依存すると思われるので、自分で「リソースの解放」を行っておく方が無難でしょう。

一般的に言って、「リソースの解放」処理が必要なクラスは、「インスタンスを生成した者が責任を持ってリソースを解放する」というのが原則です。 「インスタンスを生成した者」とはコンストラクタを呼び出した者、もしくは creation メソッド(factory メソッド)を呼び出した者です。

これを踏まえて、StreamSource, StreamResult を用いたサンプルコードは以下のようになります:

FileReader reader = null;
FileWriter writer = null;

try{
    reader = new FileReader("source.xml");
    writer = new FileWriter("result.xml");

    transformer.transform(new StreamSource(reader), new StreamResult(writer));
    writer.flush();

}finally{
    if(reader != null)
        reader.close();

    if(writer != null)
        writer.close();
}

このサンプルでは、IOException や TransformerException に対する例外処理は書いてません(外部に投げます)が、それでも finally 節は必要です。

システム ID を表す String オブジェクトやファイルを表す File オブジェクトから StreamSource, StreamResult (, SAXSource) を生成すると、上記の finally 節による「リソース解放」処理が出来ないので注意が必要です。

*1:OutputStream, Writer などの出力関係のクラスやインターフェースでは flush() メソッドも通常は必要。