GrapeCity Documents for Excel Java Edition (GcExcel) is a fast, full-featured spreadsheet library for Java developers. Compared to Apache POI, the most commonly-used spreadsheet library for Java, GcExcel is far superior in features and performance.
This post presents a comparison of their features and performance, and present the Top 12 Reasons why you should use GcExcel instead of Apache POI.
This comparison references the following build versions of GcExcel and Apache POI (excerpt from build.gradle for the benchmark app):
Here are the Top 12 Reasons to use GcExcel over Apache POI:
GcExcel is much faster and uses far less memory – performance comparisons across multiple platforms show GcExcel to be an average of 15-25 times faster and 6 times more efficient than Apache POI (see performance results below).
Some operations such as setting formulas for a large range were more than 100 times faster.
GcExcel supports 452 Calculation Functions in cell formulas, while Apache POI is lacking in support for many newer functions, with only 157-280 calculation functions available and other functions requiring implementation by the developer.
There are many more reasons to use GcExcel over Apache POI listed in the table below.
The performance tests are in the Java Console Benchmark demo code on github.
The first 3 tests populate 100,000 rows x 30 columns with values of type double, string, and date, measuring the performance for Set Values, Get Values, and Save to XLSX, and the total Memory Used (which is difficult to measure accurately since garbage collection can happen at any time).
These tests look like this (the string test uses the hard-coded string value "ABCDEFGHIJKLMNOPQRSTUVWXYZ" and the date test creates a new Date() object, but are otherwise the same):
public static void TestSetRangeValues_Double(int rowCount,
int columnCount,
RefObject<Double> setTime,
RefObject<Double> getTime,
RefObject<Double> saveTime,
RefObject<Double> usedMem) {
System.out.println();
System.out.println(String.format("GcExcel benchmark for double values with %,d rows and %d columns", rowCount, columnCount));
double startMem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
IWorkbook workbook = new Workbook();
IWorksheet worksheet = workbook.getWorksheets().get(0);
long start = System.currentTimeMillis();
double[][] values = new double[rowCount][columnCount];
for (int i = 0; i < rowCount; i++) {
for (int j = 0; j < columnCount; j++) {
values[i][j] = i + j;
}
}
worksheet.getRange(0, 0, rowCount, columnCount).setValue(values);
long end = System.currentTimeMillis();
setTime.value = (end - start) * 0.001;
System.out.println(String.format("GcExcel set double values: %.1f s", setTime.value));
start = System.currentTimeMillis();
Object tmpValues = worksheet.getRange(0, 0, rowCount, columnCount).getValue();
end = System.currentTimeMillis();
getTime.value = (end - start) * 0.001;
System.out.println(String.format("GcExcel get double values: %.1f s", getTime.value));
start = System.currentTimeMillis();
workbook.save("output/gcexcel-saved-doubles.xlsx");
end = System.currentTimeMillis();
saveTime.value = (end - start) * 0.001;
System.out.println(String.format("GcExcel save doubles to Excel: %.1f s", saveTime.value));
double endMem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
usedMem.value = (endMem - startMem) / 1024 / 1024;
System.out.println(String.format("GcExcel used memory: %.1f MB", usedMem.value));
}
The last 2 tests focus more on calculation performance. Test 4 populates 100,000 rows x 2 columns of double values, then sets formulas to a range of 100,000 rows x 30 columns adjacent to and referencing those double values in the first 2 columns, measuring the performance for Set Formulas, Calculate, Save to XLSX, and the total Memory Used.
This test looks like this:
public static void TestBigExcelFile(int rowCount,
int columnCount,
RefObject<Double> openTime,
RefObject<Double> calcTime,
RefObject<Double> saveTime,
RefObject<Double> usedMem) {
System.out.println();
System.out.println(String.format("GcExcel benchmark for test-performance.xlsx which is 20.5MB with a lot of values, formulas and styles"));
double startMem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
IWorkbook workbook = new Workbook();
long start = System.currentTimeMillis();
workbook.open("files/test-performance.xlsx");
long end = System.currentTimeMillis();
openTime.value = (end - start) * 0.001;
System.out.println(String.format("GcExcel open big Excel: %.1f s", openTime.value));
start = System.currentTimeMillis();
workbook.dirty();
workbook.calculate();
end = System.currentTimeMillis();
calcTime.value = (end - start) * 0.001;
System.out.println(String.format("GcExcel calculate formulas for big Excel: %.1f s", calcTime.value));
start = System.currentTimeMillis();
workbook.save("output/gcexcel-saved-test-performance.xlsx");
end = System.currentTimeMillis();
saveTime.value = (end - start) * 0.001;
System.out.println(String.format("GcExcel save back to big Excel: %.1f s", saveTime.value));
double endMem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
usedMem.value = (endMem - startMem) / 1024 / 1024;
System.out.println(String.format("GcExcel used memory: %.1f MB", usedMem.value));
}
Test 5 loads a large XLSX which contains many formulas using volatile functions that require recalculation each time the worksheet is calculated and measures the performance for Open File, Calculate, Save to XLSX, and the total Memory Used.
This test looks like this:
public static void TestSetRangeFormulas(int rowCount,
int columnCount,
RefObject<Double> setTime,
RefObject<Double> calcTime,
RefObject<Double> saveTime,
RefObject<Double> usedMem) {
System.out.println();
System.out.println(String.format("GcExcel benchmark for double values with %,d rows and %d columns", rowCount, columnCount));
double startMem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
IWorkbook workbook = new Workbook();
workbook.setReferenceStyle(ReferenceStyle.R1C1);
IWorksheet worksheet = workbook.getWorksheets().get(0);
double[][] values = new double[rowCount][2];
for (int i = 0; i < rowCount; i++) {
for (int j = 0; j < 2; j++) {
values[i][j] = i + j;
}
}
worksheet.getRange(0, 0, rowCount, 2).setValue(values);
long start = System.currentTimeMillis();
worksheet.getRange(0, 2, rowCount, columnCount).setFormula("=SUM(RC[-2],RC[-1])");
long end = System.currentTimeMillis();
setTime.value = (end - start) * 0.001;
System.out.println(String.format("GcExcel set formulas: %.1f s", setTime.value));
start = System.currentTimeMillis();
workbook.calculate();
end = System.currentTimeMillis();
calcTime.value = (end - start) * 0.001;
System.out.println(String.format("GcExcel calculates formula: %.1f s", calcTime.value));
workbook.setReferenceStyle(ReferenceStyle.A1);
start = System.currentTimeMillis();
workbook.save("output/gcexcel-saved-formulas.xlsx");
end = System.currentTimeMillis();
saveTime.value = (end - start) * 0.001;
System.out.println(String.format("GcExcel save formulas to Excel: %.1f s", saveTime.value));
double endMem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
usedMem.value = (endMem - startMem) / 1024 / 1024;
System.out.println(String.format("GcExcel used memory: %.1f MB", usedMem.value));
}
Linux: Performance: Avg 23.6 X FASTER, Memory: Avg 5.7 X MORE EFFICIENT
Windows: Performance: Avg 24.7 X FASTER, Memory: Avg 6.3 X MORE EFFICIENT
MacOS: Performance: Avg 15.3 X FASTER, Memory: Avg 6.0 X MORE EFFICIENT
The full performance details from which the calculations are made are in the following spreadsheets:
Overall, GcExcel is faster and uses less memory.
With GcExcel, you can command total control of your spreadsheets—with no dependencies on Excel.
If you have a comment or question about this tutorial, please leave your comments in the thread below.