AAAAAAAAAAAAAAApache POI

В разработке корпоративных приложений рано или поздно приходиться работать с различными электронными документами: таблицами и текстовыми документами (в основном в форматах .xls, .xlsx, .doc, .docx). В Java для этих целей существует чудесная библиотека с открытым исходным кодом: Apache POI. При всей прекрасности и удобности этого решения, порой некоторые аспекты его работы вызывают недоумение, их я и предлагаю рассмотреть.

Пустой ли файл?

Первое, с чем мне пришлось столкнуться — элементарная проверка на то, является ли страница пустой. Так как чтение документации — занятие неблагодарное, я сразу начал искать методы с подходящей моим целям сигнатурой. На свое "счастье", первым я встретил метод Sheet#getLastRowNum. И не было предела моему удивлению, когда оказалось, что он возвращает 0 и для абсолютно пустой страницы, и для страницы с одной (самой первой строкой).

Увы и ах, но документацию пришлось почитать. А ларчик просто открывался — метод Sheet#getPhysicalNumberOfRows возвращает нужное значение (0, если строк нет, иначе что-то большее нуля).

Давайте же все-таки вчитаемся в документацию и попытаемся понять, что делает каждый метод.

Метод Sheet#getLastRowNum возвращает индекс последней строки с данными (считая с нуля). Важно понимать, что пустые строки тоже будут посчитаны. Так, если в таблице данные содержатся только на строке 46, метод вернет значение 45.

Метод же Sheet#getPhysicalNumberOfRows возвращает число непустых строк в таблице (что считается пустой строкой — вопрос интересный). Так, в предыдущем примере было бы возвращено значение 1.

А откуда строка?

При дальнейшей работе стали появляться фантомные строки, не содержащие данных. Их можно было получить по индексу, они появлялись при переборе через итератор, считались методом Sheet#getPhysicalNumberOfRows, и содержали несколько ячеек с типом CellType#BLANK

Это неочевидно на первый взгляд, но какое-либо дополнительное форматирование влияет на ячейку, а потому она будет явно создана в структуре таблицы и считана Apache POI. Да, даже если это форматирование текста в пустой ячейке. Потому я написал небольшой вспомогательный метод для проверки строки на то, является ли она пустой.

public static boolean isEmpty(Row row) {
    Iterator<Cell> iter = row.cellIterator();
    while (iter.hasNext()) {
        Cell next = iter.next();
        switch (next.getCellTypeEnum()) {
            case BOOLEAN:
            case NUMERIC:
            case FORMULA:
                return false;
            case STRING:
                if (!next.getStringCellValue().trim().isEmpty()) {
                    return false;
                }
        }
    }
    return true;
}
Возможно, мой опыт окажется кому-то полезным.
 
Засим откланиваюсь, прощайте.