M12i.

学術書・マンガ・アニメ・映画の消費活動とプログラミングについて

Apache POIのMissingCellPolicyの解説を見つけた

Apache POIJavaアプリケーションからExcelやWordのドキュメントを参照/更新するためのライブラリです。

このライブラリには「Missing Cell」とか「Blank Cell」という概念があり、その意味するところはいまいち判然としないのですが、とくに「Missing Cell」はどうやらExcelファイル上何も入力されていない、したがってファイル上もそもそもそのセルという容れ物にかんするデータすら存在しない領域のセルはこの扱いになるようです(「Missing Cell」はExcelファイル上に物理的実体を持たないもの、「Blank Cell」は物理的実体は持つものの値が設定されておらず文字通り「空」のセルとしてマークされているもののようです)。

問題になるのはアプリケーションからExcelファイル内の一連の行(Rowインターフェース)やセル(Cellインターフェース)を取得しては値を参照したり更新したりを繰り返すとき、上述の領域に属する行やセルに関してSheet#getRow(int)Row#getCell(int)メソッドはnullを返すということです。

単に参照を求められたからといって都度勝手に行やセルを表わすデータを作ってしまえばファイルサイズやメモリサイズの問題が起きてしまいます。したがってこの動作は理解できるものではありますが、Sheet#getRow(int)Row#getCell(int)を実行した後戻り値をチェックして必要ならSheet#createRow(int)Row#createCell(int)を実行する・・・というのはいかにも面倒くさい。

Apache POIではこの問題に2つの対策を提供しています。その1つ目はCellUtilであり、このユーティリティが備えるgetCell(Row, int)getRow(int, Sheet)は上述のチェックを自動で行い非nullの戻り値を約束してくれます(Javadoc。それにしても引数の順序の不揃いが気になりますね!)。

もう1つはセル限定ですがRow#getCell(int, MissingCellPolicy)メソッドです。この第2引数に適切な列挙型のインスタンスを渡すことでメソッドの挙動を制御できるのです・・・が、APIドキュメント(Javadoc)には「どう」制御できるのか記載がありません。

コレに対してちょっとばかり調べるとstackoverflowに"Missing cell policy of Apache POI Java"というエントリーが見つかりました。ここで回答者の方が説明してくれているところによれば:

  • CREATE_NULL_AS_BLANK - If the Cell returned doesn't exist, instead of returning null, create a new Cell with a cell type of "blank". This can help avoid NullPointerExceptions conveniently.
  • RETURN_BLANK_AS_NULL - Even if the cell exists but has a cell type of "blank", return null. This can allow you ignore blank cells that do exist easily.
  • RETURN_NULL_AND_BLANK - Don't modify the existing structure; return null for cells that don't really exist and return the blank Cell if it exists but its cell type is blank. This is the behavior of the getCell overload that doesn't take a MissingCellPolicy.

つまり:

  • CREATE_NULL_AS_BLANK - もし指定されたカラム(列)のセルが存在しなければ、nullを返す代わりに、セル種別が"blank"である新しいセルを作成して返す。これはNullPointerExceptionsの発生を防ぐのに便利である。
  • RETURN_BLANK_AS_NULL - 指定されたセルは存在するがセル種別が"blank"である場合もnullを返す。これは"blank"セルを("Missing Cell"と一緒くたに)無視するのに便利である。
  • RETURN_NULL_AND_BLANK - 現に存在しているデータ構造に対して何も手を加えない。セルが本当に存在しないときだけnullを返し、セルが存在するが"blank"である場合はセル種別が"blank"のセルを返す。これはMissingCellPolicyを引数に取らないgetCell(int)メソッドと同じ挙動である。

こうしてあえて説明されれば列挙型のインスタンスの識別子も「なるほど」という感じがしますが、そうでなければ何だかよくわかりませんよね。。。(私だけでしょうか?)