I made a few script using Apache POI in Katalon Studio to study how to read cells in an Excel sheet which was generated by Number.app on my Mac, which looks like this:
TC1
// Test Cases/TC1
import java.io.InputStream;
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;
InputStream inputStream = new FileInputStream("./sample.xlsx");
Workbook workbook = WorkbookFactory.create(inputStream);
Sheet sheet = workbook.getSheetAt(0);
// print the sheet name
println "sheet name=${sheet.getSheetName()}"
// iterate over the rows contained
for (int rx = sheet.getFirstRowNum(); rx <= sheet.getLastRowNum(); rx++) { // Iterate over each row
Row row = sheet.getRow(rx);
for (int cx = row.getFirstCellNum(); cx <= row.getLastCellNum(); cx++) { // Iterate over each cell in the row
Cell cell = row.getCell(cx)
StringBuilder sb = new StringBuilder();
sb.append("(${rx},${cx})");
sb.append(" \'");
sb.append(cell.toString())
sb.append("\'");
System.out.println(sb.toString()); // Print cell value
}
System.out.println(); // New line after each row
}
inputStream.close();
TC1 emitted the following result:
2026-06-17 18:23:33.044 INFO c.k.katalon.core.main.TestCaseExecutor - START Test Cases/TC1
sheet name=Sheet1
(0,0) '表1'
(0,1) ''
(0,2) ''
(0,3) ''
(0,4) ''
(0,5) ''
(0,6) ''
(0,7) 'null'
(1,0) 'id'
(1,1) 'name'
(1,2) 'age'
(1,3) 'email'
(1,4) ''
(1,5) ''
(1,6) ''
(1,7) 'null'
(2,0) '1.0'
(2,1) 'foo'
(2,2) '18.0'
(2,3) 'foo@gmail.com'
(2,4) ''
(2,5) ''
(2,6) ''
(2,7) 'null'
(3,0) ''
(3,1) ''
(3,2) ''
(3,3) ''
(3,4) ''
(3,5) ''
(3,6) ''
(3,7) 'null'
(4,0) '2.0'
(4,1) 'bar'
(4,2) ''
(4,3) 'bar@gmail.com'
(4,4) ''
(4,5) ''
(4,6) ''
(4,7) 'null'
(5,0) ''
(5,1) ''
(5,2) ''
(5,3) ''
(5,4) ''
(5,5) ''
(5,6) ''
(5,7) 'null'
(6,0) ''
(6,1) ''
(6,2) ''
(6,3) ''
(6,4) ''
(6,5) ''
(6,6) ''
(6,7) 'null'
(7,0) ''
(7,1) ''
(7,2) ''
(7,3) ''
(7,4) ''
(7,5) ''
(7,6) ''
(7,7) 'null'
(8,0) ''
(8,1) ''
(8,2) ''
(8,3) ''
(8,4) ''
(8,5) ''
(8,6) ''
(8,7) 'null'
(9,0) ''
(9,1) ''
(9,2) ''
(9,3) ''
(9,4) ''
(9,5) ''
(9,6) ''
(9,7) 'null'
(10,0) ''
(10,1) ''
(10,2) ''
(10,3) ''
(10,4) ''
(10,5) ''
(10,6) ''
(10,7) 'null'
(11,0) ''
(11,1) ''
(11,2) ''
(11,3) ''
(11,4) ''
(11,5) ''
(11,6) ''
(11,7) 'null'
(12,0) ''
(12,1) ''
(12,2) ''
(12,3) ''
(12,4) ''
(12,5) ''
(12,6) ''
(12,7) 'null'
(13,0) ''
(13,1) ''
(13,2) ''
(13,3) ''
(13,4) ''
(13,5) ''
(13,6) ''
(13,7) 'null'
(14,0) ''
(14,1) ''
(14,2) ''
(14,3) ''
(14,4) ''
(14,5) ''
(14,6) ''
(14,7) 'null'
(15,0) ''
(15,1) ''
(15,2) ''
(15,3) ''
(15,4) ''
(15,5) ''
(15,6) ''
(15,7) 'null'
(16,0) ''
(16,1) ''
(16,2) ''
(16,3) ''
(16,4) ''
(16,5) ''
(16,6) ''
(16,7) 'null'
(17,0) ''
(17,1) ''
(17,2) ''
(17,3) ''
(17,4) ''
(17,5) ''
(17,6) ''
(17,7) 'null'
(18,0) ''
(18,1) ''
(18,2) ''
(18,3) ''
(18,4) ''
(18,5) ''
(18,6) ''
(18,7) 'null'
(19,0) ''
(19,1) ''
(19,2) ''
(19,3) ''
(19,4) ''
(19,5) ''
(19,6) ''
(19,7) 'null'
(20,0) ''
(20,1) ''
(20,2) ''
(20,3) ''
(20,4) ''
(20,5) ''
(20,6) ''
(20,7) 'null'
(21,0) ''
(21,1) ''
(21,2) ''
(21,3) ''
(21,4) ''
(21,5) ''
(21,6) ''
(21,7) 'null'
(22,0) ''
(22,1) ''
(22,2) ''
(22,3) ''
(22,4) ''
(22,5) ''
(22,6) ''
(22,7) 'null'
TC2
// Test Cases/TC2
import java.io.InputStream;
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;
InputStream inputStream = new FileInputStream("./sample.xlsx");
Workbook workbook = WorkbookFactory.create(inputStream);
Sheet sheet = workbook.getSheetAt(0);
// print the sheet name
println "sheet name=${sheet.getSheetName()}"
// iterate over the rows contained
for (int rx = sheet.getFirstRowNum(); rx <= sheet.getLastRowNum(); rx++) { // Iterate over each row
Row row = sheet.getRow(rx);
for (int cx = row.getFirstCellNum(); cx <= row.getLastCellNum(); cx++) { // Iterate over each cell in the row
Cell cell = row.getCell(cx)
if (cell != null) {
StringBuilder sb = new StringBuilder();
sb.append("(${rx},${cx})");
sb.append(" \'");
sb.append(cell.toString())
sb.append("\'");
System.out.println(sb.toString()); // Print cell value
} else {
System.out.println("(${rx},${cx}) is null")
}
}
System.out.println(); // New line after each row
}
inputStream.close();
TC2 emitted the following
2026-06-17 18:25:46.835 INFO c.k.katalon.core.main.TestCaseExecutor - START Test Cases/TC2
sheet name=Sheet1
(0,0) '表1'
(0,1) ''
(0,2) ''
(0,3) ''
(0,4) ''
(0,5) ''
(0,6) ''
(0,7) is null
(1,0) 'id'
(1,1) 'name'
(1,2) 'age'
(1,3) 'email'
(1,4) ''
(1,5) ''
(1,6) ''
(1,7) is null
(2,0) '1.0'
(2,1) 'foo'
(2,2) '18.0'
(2,3) 'foo@gmail.com'
(2,4) ''
(2,5) ''
(2,6) ''
(2,7) is null
(3,0) ''
(3,1) ''
(3,2) ''
(3,3) ''
(3,4) ''
(3,5) ''
(3,6) ''
(3,7) is null
(4,0) '2.0'
(4,1) 'bar'
(4,2) ''
(4,3) 'bar@gmail.com'
(4,4) ''
(4,5) ''
(4,6) ''
(4,7) is null
(5,0) ''
(5,1) ''
(5,2) ''
(5,3) ''
(5,4) ''
(5,5) ''
(5,6) ''
(5,7) is null
(6,0) ''
(6,1) ''
(6,2) ''
(6,3) ''
(6,4) ''
(6,5) ''
(6,6) ''
(6,7) is null
(7,0) ''
(7,1) ''
(7,2) ''
(7,3) ''
(7,4) ''
(7,5) ''
(7,6) ''
(7,7) is null
(8,0) ''
(8,1) ''
(8,2) ''
(8,3) ''
(8,4) ''
(8,5) ''
(8,6) ''
(8,7) is null
(9,0) ''
(9,1) ''
(9,2) ''
(9,3) ''
(9,4) ''
(9,5) ''
(9,6) ''
(9,7) is null
(10,0) ''
(10,1) ''
(10,2) ''
(10,3) ''
(10,4) ''
(10,5) ''
(10,6) ''
(10,7) is null
(11,0) ''
(11,1) ''
(11,2) ''
(11,3) ''
(11,4) ''
(11,5) ''
(11,6) ''
(11,7) is null
(12,0) ''
(12,1) ''
(12,2) ''
(12,3) ''
(12,4) ''
(12,5) ''
(12,6) ''
(12,7) is null
(13,0) ''
(13,1) ''
(13,2) ''
(13,3) ''
(13,4) ''
(13,5) ''
(13,6) ''
(13,7) is null
(14,0) ''
(14,1) ''
(14,2) ''
(14,3) ''
(14,4) ''
(14,5) ''
(14,6) ''
(14,7) is null
(15,0) ''
(15,1) ''
(15,2) ''
(15,3) ''
(15,4) ''
(15,5) ''
(15,6) ''
(15,7) is null
(16,0) ''
(16,1) ''
(16,2) ''
(16,3) ''
(16,4) ''
(16,5) ''
(16,6) ''
(16,7) is null
(17,0) ''
(17,1) ''
(17,2) ''
(17,3) ''
(17,4) ''
(17,5) ''
(17,6) ''
(17,7) is null
(18,0) ''
(18,1) ''
(18,2) ''
(18,3) ''
(18,4) ''
(18,5) ''
(18,6) ''
(18,7) is null
(19,0) ''
(19,1) ''
(19,2) ''
(19,3) ''
(19,4) ''
(19,5) ''
(19,6) ''
(19,7) is null
(20,0) ''
(20,1) ''
(20,2) ''
(20,3) ''
(20,4) ''
(20,5) ''
(20,6) ''
(20,7) is null
(21,0) ''
(21,1) ''
(21,2) ''
(21,3) ''
(21,4) ''
(21,5) ''
(21,6) ''
(21,7) is null
(22,0) ''
(22,1) ''
(22,2) ''
(22,3) ''
(22,4) ''
(22,5) ''
(22,6) ''
(22,7) is null
2026-06-17 18:25:49.885 INFO c.k.katalon.core.main.TestCaseExecutor - END Test Cases/TC2
TC3
// Test Cases/TC3
import java.io.InputStream;
import java.io.FileInputStream;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.util.CellAddress;
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;
InputStream inputStream = new FileInputStream("./sample.xlsx");
Workbook workbook = WorkbookFactory.create(inputStream);
Sheet sheet = workbook.getSheetAt(0);
// print the sheet name
println "sheet name=${sheet.getSheetName()}"
// iterate over the rows contained
for (Row row : sheet) { // Iterate over each row
for (Cell cell : row) { // Iterate over each cell in the row
CellAddress cellAddress = cell.getAddress();
StringBuilder sb = new StringBuilder();
sb.append(cellAddress.formatAsR1C1String());
sb.append(" \'");
sb.append(cell.toString())
sb.append("\'");
System.out.println(sb.toString()); // Print cell value
}
System.out.println(); // New line after each row
}
inputStream.close();
TC3 emitted the following
2026-06-17 18:27:38.144 INFO c.k.katalon.core.main.TestCaseExecutor - START Test Cases/TC3
sheet name=Sheet1
R1C1 '表1'
R1C2 ''
R1C3 ''
R1C4 ''
R1C5 ''
R1C6 ''
R1C7 ''
R2C1 'id'
R2C2 'name'
R2C3 'age'
R2C4 'email'
R2C5 ''
R2C6 ''
R2C7 ''
R3C1 '1.0'
R3C2 'foo'
R3C3 '18.0'
R3C4 'foo@gmail.com'
R3C5 ''
R3C6 ''
R3C7 ''
R4C1 ''
R4C2 ''
R4C3 ''
R4C4 ''
R4C5 ''
R4C6 ''
R4C7 ''
R5C1 '2.0'
R5C2 'bar'
R5C3 ''
R5C4 'bar@gmail.com'
R5C5 ''
R5C6 ''
R5C7 ''
R6C1 ''
R6C2 ''
R6C3 ''
R6C4 ''
R6C5 ''
R6C6 ''
R6C7 ''
R7C1 ''
R7C2 ''
R7C3 ''
R7C4 ''
R7C5 ''
R7C6 ''
R7C7 ''
R8C1 ''
R8C2 ''
R8C3 ''
R8C4 ''
R8C5 ''
R8C6 ''
R8C7 ''
R9C1 ''
R9C2 ''
R9C3 ''
R9C4 ''
R9C5 ''
R9C6 ''
R9C7 ''
R10C1 ''
R10C2 ''
R10C3 ''
R10C4 ''
R10C5 ''
R10C6 ''
R10C7 ''
R11C1 ''
R11C2 ''
R11C3 ''
R11C4 ''
R11C5 ''
R11C6 ''
R11C7 ''
R12C1 ''
R12C2 ''
R12C3 ''
R12C4 ''
R12C5 ''
R12C6 ''
R12C7 ''
R13C1 ''
R13C2 ''
R13C3 ''
R13C4 ''
R13C5 ''
R13C6 ''
R13C7 ''
R14C1 ''
R14C2 ''
R14C3 ''
R14C4 ''
R14C5 ''
R14C6 ''
R14C7 ''
R15C1 ''
R15C2 ''
R15C3 ''
R15C4 ''
R15C5 ''
R15C6 ''
R15C7 ''
R16C1 ''
R16C2 ''
R16C3 ''
R16C4 ''
R16C5 ''
R16C6 ''
R16C7 ''
R17C1 ''
R17C2 ''
R17C3 ''
R17C4 ''
R17C5 ''
R17C6 ''
R17C7 ''
R18C1 ''
R18C2 ''
R18C3 ''
R18C4 ''
R18C5 ''
R18C6 ''
R18C7 ''
R19C1 ''
R19C2 ''
R19C3 ''
R19C4 ''
R19C5 ''
R19C6 ''
R19C7 ''
R20C1 ''
R20C2 ''
R20C3 ''
R20C4 ''
R20C5 ''
R20C6 ''
R20C7 ''
R21C1 ''
R21C2 ''
R21C3 ''
R21C4 ''
R21C5 ''
R21C6 ''
R21C7 ''
R22C1 ''
R22C2 ''
R22C3 ''
R22C4 ''
R22C5 ''
R22C6 ''
R22C7 ''
R23C1 ''
R23C2 ''
R23C3 ''
R23C4 ''
R23C5 ''
R23C6 ''
R23C7 ''
2026-06-17 18:27:41.028 INFO c.k.katalon.core.main.TestCaseExecutor - END Test Cases/TC3
My opinion
TC3 is better than TC1 and TC2.
TC3 uses Sheet.iterator() and Row.interator(). These methods gives you a logical view without NULL objects. Using these methods, you would encounter no null; so you would not get NullPointerException.
TC1 and TC2 use getFirstRowNum(), getLastRowNum(), getRow() methods of Sheet class; getFistCellNum(), getLastCellNum(), getCell() methods of Row class. You would be tempted to use them in a loop of for (int i = theFirstIndex; i < theLastIndex; i**) { Cell cell = row.getCell(i) }. The row.getCell(i) is quite liketly to return null. When you use these methods, you have to be very careful about NULL.
I would recommend you Not to use getFirstRowNum() and the following INDEX-based access to the physical view.
You should prefer the builtin iterator() methods.