Apache POI で拡張for文を使うときの注意点

# これは何？
Apache Poiを使ってExcelを読み込むプログラムを書いた時にはまったのでメモ。

# 環境
- Java8(jdk1.8.0_102)
- Apache Poi(3.14)
- eclipse

# 再現メモ
## Maven
```xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>apachePoiTest</groupId>
	<artifactId>apachePoiTest</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<dependencies>
		<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>3.14</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>3.14</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml-schemas -->
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml-schemas</artifactId>
			<version>3.14</version>
		</dependency>
	</dependencies>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<javac.target>1.8</javac.target>
	</properties>


</project>
```

## Java

```java
package apachePoiTest;

import java.io.FileInputStream;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;

public class Test {

	private static final String xlsxFileAddress = "G:\\work\\Test.xlsx";

	public static void main(String[] args) {
		try {

			// 共通インターフェースを扱える、WorkbookFactoryで読み込む
			Workbook wb = WorkbookFactory.create(new FileInputStream(xlsxFileAddress));

			// 全セルを表示する
			for (Sheet sheet : wb) {
				for (Row row : sheet) {

					test1(row);
					System.out.println();
					test2(row);

				}
			}

			wb.close();

		} catch (Exception e) {
			e.printStackTrace();
		} finally {

		}

	}

	private static void test1(Row row) {

		System.out.println("標準のfor文で回すパターン");

		for (int i = 0; i < 5; i++) {
			Cell cell = row.getCell(i);
			System.out.print(getCellValue(cell));
			System.out.print(" , ");
		}
		System.out.println();

	}

	private static void test2(Row row) {

		System.out.println("拡張for文で回すパターン");
		for (Cell cell : row) {
			System.out.print(getCellValue(cell));
			System.out.print(" , ");
		}
		System.out.println();

	}

	private static Object getCellValue(Cell cell) {

		if (cell == null) {
			return "";
		}

		switch (cell.getCellType()) {

		case Cell.CELL_TYPE_STRING:
			return cell.getRichStringCellValue().getString();

		case Cell.CELL_TYPE_NUMERIC:
			return cell.getNumericCellValue();

		case Cell.CELL_TYPE_BOOLEAN:
			return cell.getBooleanCellValue();

		case Cell.CELL_TYPE_FORMULA:
			return cell.getCellFormula();

		default:
			return null;

		}

	}
}

```

## テスト用Excel
![excel.PNG](https://qiita-image-store.s3.amazonaws.com/0/77910/55a47e30-8953-3c2d-b3d8-34772118cebf.png)

# 何が起こるのか
拡張For文でcellを読んだ時は、D1のセルが読み飛ばされてしまう。

```
標準のfor文で回すパターン
Cell1 , Cell2 , Cell3 ,  , Cell5 , 

拡張for文で回すパターン
Cell1 , Cell2 , Cell3 , Cell5 , 
```

# 結論
- 空白がある可能性があるExcelデータを読み込むときは、セルの数は事前に確認してfor文で回す回数を明記すること。
- 拡張for文は便利だけど、このようなトラップもあるということを知っておく必要がある。（普通のListとか配列なら問題ないけど）

# 有識者へのお願い
この仕様について明記されている資料等知ってましたら教えてください。