从基础到高级详解Java读写Excel公式的实战指南

 更新时间:2026年05月25日 08:56:44   作者:SunnyDays1011  
这篇文章主要为大家详细介绍了Java使用Spireire.XLSforJava处理Excel公式的方法,涵盖写入、读取、跨工作表引用、日期时间函数等操作,希望对大家有所帮助

做数据处理的朋友应该都遇到过这种场景:需要批量生成带公式的Excel报表,或者读取现有表格中的公式进行二次计算。以前我都是手动在Excel里写公式,后来发现用Java代码来处理更高效,尤其是数据量大的时候。

今天整理一下平时用得比较多的几种Excel公式处理方式,希望能给有同样需求的朋友一些参考。

环境准备

使用的库

本文示例使用的是 Spire.XLS for Java,这是一个专门处理Excel文件的Java库。如果你项目中已经在用Apache POI,也可以实现类似功能,不过API会有些不同。

安装方式

Maven项目,在 pom.xml 中添加依赖:

<repositories>
    <repository>
        <id>com.e-iceblue</id>
        <name>e-iceblue</name>
        <url>https://repo.e-iceblue.cn/repository/maven-public/</url>
    </repository>
</repositories>
<dependencies>
    <dependency>
        <groupId>e-iceblue</groupId>
        <artifactId>spire.xls</artifactId>
        <version>14.12.0</version>
    </dependency>
</dependencies>

Gradle项目,在 build.gradle 中添加:

repositories {
    maven {
        url 'https://repo.e-iceblue.cn/repository/maven-public/'
    }
}
dependencies {
    implementation 'e-iceblue:spire.xls:14.12.0'
}

或者直接下载JAR包从官网导入项目。

一、最基础的:写入和读取公式

1. 写入常见公式

最常见的就是往单元格里写公式了。比如SUM、AVERAGE这些统计函数:

import com.spire.xls.*;

public class WriteFormulas {
    public static void main(String[] args) {
        // 创建工作簿
        Workbook workbook = new Workbook();
        
        // 获取第一个工作表
        Worksheet sheet = workbook.getWorksheets().get(0);
        
        // 准备测试数据
        sheet.getCellRange("B2").setNumberValue(7.3);
        sheet.getCellRange("C2").setNumberValue(5);
        sheet.getCellRange("D2").setNumberValue(8.2);
        
        // 写入求和公式
        sheet.getCellRange("E2").setFormula("=SUM(B2:D2)");
        
        // 写入平均值公式
        sheet.getCellRange("F2").setFormula("=AVERAGE(B2:D2)");
        
        // 保存文件
        workbook.saveToFile("result.xlsx", ExcelVersion.Version2013);
        
        // 释放资源
        workbook.dispose();
        
        System.out.println("文件已生成!");
    }
}

注意一个小细节:如果想在单元格里显示公式文本而不是计算结果,需要在前面加个单引号:

// 这样单元格会显示 "=SUM(B2:D2)" 这个文本
sheet.getCellRange("A2").setText("'=SUM(B2:D2)");

2. 读取已有公式

有时候需要读取现成Excel文件里的公式,看看是怎么计算的:

Workbook workbook = new Workbook();
workbook.loadFromFile("existing.xlsx");
Worksheet sheet = workbook.getWorksheets().get(0);

// 获取公式字符串
String formula = sheet.getCellRange("C14").getFormula();
System.out.println("公式: " + formula);

// 获取公式计算结果
double value = sheet.getCellRange("C14").getFormulaNumberValue();
System.out.println("结果: " + value);

这个功能在做公式审计或者模板分析时特别有用。

二、跨工作表引用

实际项目中经常需要跨Sheet引用数据,写法跟Excel里一样:

// 引用Sheet1的B3单元格
sheet.getCellRange("A1").setFormula("=Sheet1!$B$3");

// 引用某个区域的平均值
sheet.getCellRange("A2").setFormula("=AVERAGE(Sheet1!$D$3:G$3)");

绝对引用(带$符号)和相对引用的区别一定要搞清楚,不然复制公式时容易出错。

三、日期和时间函数

处理时间相关的报表时,这几个函数很实用:

// 当前日期时间
sheet.getCellRange("A1").setFormula("=NOW()");
sheet.getCellRange("A1").getCellStyle().setNumberFormat("yyyy-MM-DD HH:mm:ss");

// 提取年、月、日
sheet.getCellRange("B1").setFormula("=YEAR(TODAY())");
sheet.getCellRange("C1").setFormula("=MONTH(TODAY())");
sheet.getCellRange("D1").setFormula("=DAY(TODAY())");

// 提取时、分、秒
sheet.getCellRange("E1").setFormula("=HOUR(NOW())");
sheet.getCellRange("F1").setFormula("=MINUTE(NOW())");
sheet.getCellRange("G1").setFormula("=SECOND(NOW())");

// 星期几
sheet.getCellRange("H1").setFormula("=WEEKDAY(TODAY())");

NOW()函数每次打开文件都会重新计算,如果需要固定时间,建议计算后转成静态值。

四、数学和统计函数

除了基本的SUM、AVERAGE,还有一些常用的:

// 最大值、最小值
sheet.getCellRange("A1").setFormula("=MAX(10,30,50)");
sheet.getCellRange("A2").setFormula("=MIN(5,7,3)");

// 四舍五入
sheet.getCellRange("A3").setFormula("=ROUND(3.14159, 2)");  // 结果: 3.14

// 取整
sheet.getCellRange("A4").setFormula("=INT(9.8)");  // 结果: 9

// 绝对值
sheet.getCellRange("A5").setFormula("=ABS(-15.6)");  // 结果: 15.6

// 平方根
sheet.getCellRange("A6").setFormula("=SQRT(144)");  // 结果: 12

// 随机数
sheet.getCellRange("A7").setFormula("=RAND()");  // 0-1之间的随机数

五、逻辑函数

条件判断在报表中很常见:

// IF函数
sheet.getCellRange("A1").setFormula("=IF(B1>60, \"及格\", \"不及格\")");

// AND、OR
sheet.getCellRange("A2").setFormula("=AND(B1>60, C1>60)");
sheet.getCellRange("A3").setFormula("=OR(B1>90, C1>90)");

// NOT
sheet.getCellRange("A4").setFormula("=NOT(TRUE)");  // 结果: FALSE

实际应用:用IF嵌套来做成绩等级划分:

"=IF(A1>=90, \"优秀\", IF(A1>=80, \"良好\", IF(A1>=60, \"及格\", \"不及格\")))"

六、文本函数

处理字符串时也少不了公式:

// 字符串长度
sheet.getCellRange("A1").setFormula("=LEN(\"Hello World\")");  // 结果: 11

// 截取子串
sheet.getCellRange("A2").setFormula("=MID(\"Hello World\", 7, 5)");  // 结果: World

// 类型转换
sheet.getCellRange("A3").setFormula("=VALUE(\"123\")");  // 文本转数字

七、数组公式(高级用法)

数组公式可以一次性对多个值进行计算,适合复杂的数据分析:

// 准备数据
sheet.getCellRange("A1").setNumberValue(1);
sheet.getCellRange("A2").setNumberValue(2);
sheet.getCellRange("A3").setNumberValue(3);
sheet.getCellRange("B1").setNumberValue(4);
sheet.getCellRange("B2").setNumberValue(5);
sheet.getCellRange("B3").setNumberValue(6);

// 设置数组公式(线性回归)
sheet.getCellRange("A5:C6").setFormulaArray("=LINEST(A1:A3,B1:B3,TRUE,TRUE)");

// 计算公式值
workbook.calculateAllValue();

使用场景:财务分析、统计建模时会用到这类高级函数。

八、不依赖Excel直接计算公式值

有时候不需要生成Excel文件,只是想算个公式的结果,可以直接计算:

Workbook workbook = new Workbook();

// 直接计算公式的值
Object result1 = workbook.calculateFormulaValue("=10+20*3");
System.out.println(result1);  // 结果: 70

Object result2 = workbook.calculateFormulaValue("=SUM(1,2,3,4,5)");
System.out.println(result2);  // 结果: 15

// 甚至可以引用单元格
workbook.getWorksheets().get(0).getCellRange("A1").setNumberValue(100);
Object result3 = workbook.calculateFormulaValue("=A1*2");
System.out.println(result3);  // 结果: 200

这个功能在做快速计算或者公式验证时很方便,不用真的创建Excel文件。

九、移除公式保留计算结果

有个实际需求:给客户发报表时,只想给他们看最终数据,不想暴露计算公式。这时候可以把公式转成静态值:

Workbook workbook = new Workbook();
workbook.loadFromFile("with_formulas.xlsx");

for (Worksheet sheet : (Iterable<Worksheet>) workbook.getWorksheets()) {
    for (CellRange cell : (Iterable<CellRange>) sheet.getRange()) {
        if (cell.hasFormula()) {
            // 获取公式计算结果
            Object value = cell.getFormulaValue();
            
            // 清除公式
            cell.clear(ExcelClearOptions.ClearContent);
            
            // 设置为静态值
            cell.setValue(value.toString());
        }
    }
}

workbook.saveToFile("without_formulas.xlsx", ExcelVersion.Version2013);

应用场景:财务报表、对外发布的统计数据等需要保护公式逻辑的场景。

十、Excel 2013+的新函数

新版Excel增加了一些实用函数,比如位运算、URL编码等:

// 位运算
sheet.getCellRange("A1").setFormula("=BITOR(23,10)");    // 按位或
sheet.getCellRange("A2").setFormula("=BITAND(23,10)");   // 按位与
sheet.getCellRange("A3").setFormula("=BITLSHIFT(23,2)"); // 左移
sheet.getCellRange("A4").setFormula("=BITRSHIFT(23,2)"); // 右移

// URL编码
sheet.getCellRange("A5").setFormula("=ENCODEURL(\"https://example.com\")");

// ISO周数
sheet.getCellRange("A6").setFormula("=ISOWEEKNUM(DATE(2024,1,1))");

// 精确舍入
sheet.getCellRange("A7").setFormula("=CEILING.PRECISE(-4.6, 3)");
sheet.getCellRange("A8").setFormula("=FLOOR.MATH(12.758, 2, -1)");

这些函数在处理特定业务逻辑时很有用,比如网络应用开发中的URL处理。

十一、命名范围中使用公式

如果公式里用到的区域经常变化,可以用命名范围来简化:

// 定义命名范围
Name name = workbook.getNameList().add("SalesData");
name.setRefersToRange(sheet.getCellRange("A1:A100"));

// 在公式中使用命名范围
sheet.getCellRange("B1").setFormula("=SUM(SalesData)");

这样做的好处是,当数据区域扩展时,只需要修改命名范围的定义,不用改所有公式。

十二、R1C1引用样式

除了常见的A1样式,Excel还支持R1C1引用方式(行号+列号):

// R1C1样式的公式
sheet.getCellRange("C3").setR1C1Formula("=R[-1]C[-1]+R[-1]C[0]");
// 意思是:上一行左边一格 + 上一行当前列

// 数组形式的R1C1公式
sheet.getCellRange("D3:E4").setR1C1FormulaArray("=R[-2]C[-3]:R[-1]C[-2]");

什么时候用:在程序化生成公式时,R1C1方式更容易通过坐标计算来动态构建公式。

十三、自定义函数(加载项函数)

如果遇到Excel内置函数不够用的情况,可以注册自定义函数:

// 注册加载项函数库
workbook.registerAddInFunction("MyFunctions.xll");

// 然后就可以像普通函数一样使用
sheet.getCellRange("A1").setFormula("=MYCUSTOMFUNC(B1,C1)");

适用场景:有特殊计算需求的行业,比如金融衍生品定价、工程计算等。

十四、SUBTOTAL函数(忽略隐藏行)

做数据筛选时,普通的SUM会把隐藏行也算进去,用SUBTOTAL可以避免这个问题:

// 第一个参数3表示COUNTA,只统计可见单元格
sheet.getCellRange("A1").setFormula("=SUBTOTAL(3, B2:E100)");

常用功能代码:

  • 1: AVERAGE
  • 2: COUNT
  • 3: COUNTA
  • 9: SUM
  • 109: SUM(忽略隐藏值)

十五、实际项目中的综合应用

最后分享一个实际场景:生成月度销售报表。

Workbook workbook = new Workbook();
Worksheet sheet = workbook.getWorksheets().get(0);

// 1. 写入标题
sheet.getCellRange("A1").setValue("月份");
sheet.getCellRange("B1").setValue("销售额");
sheet.getCellRange("C1").setValue("成本");
sheet.getCellRange("D1").setValue("利润");
sheet.getCellRange("E1").setValue("利润率");

// 2. 写入数据并添加公式
for (int i = 2; i <= 13; i++) {
    sheet.getCellRange("A" + i).setValue((i-1) + "月");
    sheet.getCellRange("B" + i).setNumberValue(Math.random() * 100000);
    sheet.getCellRange("C" + i).setNumberValue(Math.random() * 60000);
    
    // 利润 = 销售额 - 成本
    sheet.getCellRange("D" + i).setFormula("=B" + i + "-C" + i);
    
    // 利润率 = 利润 / 销售额
    sheet.getCellRange("E" + i).setFormula("=D" + i + "/B" + i);
    sheet.getCellRange("E" + i).getCellStyle().setNumberFormat("0.00%");
}

// 3. 添加汇总行
int lastRow = 14;
sheet.getCellRange("A" + lastRow).setValue("合计");
sheet.getCellRange("B" + lastRow).setFormula("=SUM(B2:B13)");
sheet.getCellRange("C" + lastRow).setFormula("=SUM(C2:C13)");
sheet.getCellRange("D" + lastRow).setFormula("=SUM(D2:D13)");
sheet.getCellRange("E" + lastRow).setFormula("=AVERAGE(E2:E13)");

// 4. 设置格式
sheet.getAllocatedRange().autoFitColumns();
sheet.getCellRange("A1:E1").getCellStyle().getExcelFont().isBold(true);

workbook.saveToFile("monthly_report.xlsx", ExcelVersion.Version2013);

这样一个完整的报表就生成了,所有计算都是通过公式完成的,后续修改原始数据,结果会自动更新。

小结

总结一下几个关键点:

  1. 简单公式直接用setFormula(),跟Excel里写法一致
  2. 跨表引用SheetName!CellAddress格式
  3. 数组公式setFormulaArray(),记得调用calculateAllValue()
  4. 只要计算结果不要公式,遍历单元格转换
  5. 直接计算公式值calculateFormulaValue(),不用创建文件
  6. 新函数如位运算、URL编码等,注意Excel版本兼容性

实际使用中,最重要的是理解业务需求,选择合适的公式类型。不是所有场景都需要复杂的公式,有时候简单的SUM、IF就能解决问题。

到此这篇关于从基础到高级详解Java读写Excel公式的实战指南的文章就介绍到这了,更多相关Java读写Excel公式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java 超基础讲解String的使用

    Java 超基础讲解String的使用

    字符串广泛应用 在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串,让我们一起来了解它
    2022-04-04
  • Java 自定义Spring框架以及Spring框架的基本使用

    Java 自定义Spring框架以及Spring框架的基本使用

    Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发
    2021-10-10
  • 详解Java8 新特性之日期API

    详解Java8 新特性之日期API

    Java 8 在包java.time下包含了一组全新的时间日期API。下面通过示例给大家讲解java8 新特征日期api的相关知识,感兴趣的朋友一起看看吧
    2017-07-07
  • Spring的FactoryBean<Object>接口示例代码

    Spring的FactoryBean<Object>接口示例代码

    FactoryBean是Spring框架中的一个接口,用于创建和管理Bean对象,它的作用是将Bean的创建过程交给FactoryBean实现类来完成,而不是直接由Spring容器来创建,本文给大家介绍Spring的FactoryBean<Object>接口,感兴趣的朋友一起看看吧
    2023-11-11
  • JavaScript 与 Java 区别介绍  学java怎么样

    JavaScript 与 Java 区别介绍 学java怎么样

    JavaScript 是一种嵌入式脚本文件,直接插入网页,有浏览器一边解释一边执行。而java 语言不一样,他必须在JAVA虚拟机上运行。而且事先需要进行编译。接下来脚本之家小编给大家揭晓js与java区别,感兴趣的朋友一起看看吧
    2016-09-09
  • SpringMVC之简单的增删改查示例(SSM整合)

    SpringMVC之简单的增删改查示例(SSM整合)

    本篇文章主要介绍了SpringMVC之简单的增删改查示例(SSM整合),这个例子是基于SpringMVC+Spring+Mybatis实现的。有兴趣的可以了解一下。
    2017-03-03
  • Java整合mybatis实现过滤数据

    Java整合mybatis实现过滤数据

    这篇文章主要介绍了Java整合mybatis实现过滤数据,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2023-01-01
  • SpringMvc获取页面中的参数方法详解

    SpringMvc获取页面中的参数方法详解

    这篇文章主要介绍了SpringMvc获取页面中的参数方法详解,获取页面的参数通常都是让类实现设置HttpServletRequest request接口然后重写接口中的方法的办法来得到参数,但是在Springmvc中有其他的获取方法,需要的朋友可以参考下
    2023-10-10
  • jdbc连接sqlserver数据库示例

    jdbc连接sqlserver数据库示例

    这篇文章主要介绍了jdbc连接sqlserver数据库示例,需要的朋友可以参考下
    2014-04-04
  • 利用Spring Validation实现输入验证功能

    利用Spring Validation实现输入验证功能

    这篇文章主要给大家介绍了如何利用Spring Validation完美的实现输入验证功能,文中有详细的代码示例,具有一定的参考价值,感兴趣的朋友可以借鉴一下
    2023-06-06

最新评论