当前位置: 首页 > news >正文

Java 读写 Excel 公式:从基础到高级的实战总结

做数据处理的朋友应该都遇到过这种场景需要批量生成带公式的Excel报表或者读取现有表格中的公式进行二次计算。以前我都是手动在Excel里写公式后来发现用Java代码来处理更高效尤其是数据量大的时候。今天整理一下平时用得比较多的几种Excel公式处理方式希望能给有同样需求的朋友一些参考。环境准备使用的库本文示例使用的是Spire.XLS for Java这是一个专门处理Excel文件的Java库。如果你项目中已经在用Apache POI也可以实现类似功能不过API会有些不同。安装方式Maven项目在pom.xml中添加依赖repositoriesrepositoryidcom.e-iceblue/idnamee-iceblue/nameurlhttps://repo.e-iceblue.cn/repository/maven-public//url/repository/repositoriesdependenciesdependencygroupIde-iceblue/groupIdartifactIdspire.xls/artifactIdversion14.12.0/version/dependency/dependenciesGradle项目在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这些统计函数importcom.spire.xls.*;publicclassWriteFormulas{publicstaticvoidmain(String[]args){// 创建工作簿WorkbookworkbooknewWorkbook();// 获取第一个工作表Worksheetsheetworkbook.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文件里的公式看看是怎么计算的WorkbookworkbooknewWorkbook();workbook.loadFromFile(existing.xlsx);Worksheetsheetworkbook.getWorksheets().get(0);// 获取公式字符串Stringformulasheet.getCellRange(C14).getFormula();System.out.println(公式: formula);// 获取公式计算结果doublevaluesheet.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(B160, \及格\, \不及格\));// AND、ORsheet.getCellRange(A2).setFormula(AND(B160, C160));sheet.getCellRange(A3).setFormula(OR(B190, C190));// NOTsheet.getCellRange(A4).setFormula(NOT(TRUE));// 结果: FALSE实际应用用IF嵌套来做成绩等级划分IF(A190, \优秀\, IF(A180, \良好\, IF(A160, \及格\, \不及格\)))六、文本函数处理字符串时也少不了公式// 字符串长度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文件只是想算个公式的结果可以直接计算WorkbookworkbooknewWorkbook();// 直接计算公式的值Objectresult1workbook.calculateFormulaValue(1020*3);System.out.println(result1);// 结果: 70Objectresult2workbook.calculateFormulaValue(SUM(1,2,3,4,5));System.out.println(result2);// 结果: 15// 甚至可以引用单元格workbook.getWorksheets().get(0).getCellRange(A1).setNumberValue(100);Objectresult3workbook.calculateFormulaValue(A1*2);System.out.println(result3);// 结果: 200这个功能在做快速计算或者公式验证时很方便不用真的创建Excel文件。九、移除公式保留计算结果有个实际需求给客户发报表时只想给他们看最终数据不想暴露计算公式。这时候可以把公式转成静态值WorkbookworkbooknewWorkbook();workbook.loadFromFile(with_formulas.xlsx);for(Worksheetsheet:(IterableWorksheet)workbook.getWorksheets()){for(CellRangecell:(IterableCellRange)sheet.getRange()){if(cell.hasFormula()){// 获取公式计算结果Objectvaluecell.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处理。十一、命名范围中使用公式如果公式里用到的区域经常变化可以用命名范围来简化// 定义命名范围Namenameworkbook.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: AVERAGE2: COUNT3: COUNTA9: SUM109: SUM忽略隐藏值十五、实际项目中的综合应用最后分享一个实际场景生成月度销售报表。WorkbookworkbooknewWorkbook();Worksheetsheetworkbook.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(inti2;i13;i){sheet.getCellRange(Ai).setValue((i-1)月);sheet.getCellRange(Bi).setNumberValue(Math.random()*100000);sheet.getCellRange(Ci).setNumberValue(Math.random()*60000);// 利润 销售额 - 成本sheet.getCellRange(Di).setFormula(Bi-Ci);// 利润率 利润 / 销售额sheet.getCellRange(Ei).setFormula(Di/Bi);sheet.getCellRange(Ei).getCellStyle().setNumberFormat(0.00%);}// 3. 添加汇总行intlastRow14;sheet.getCellRange(AlastRow).setValue(合计);sheet.getCellRange(BlastRow).setFormula(SUM(B2:B13));sheet.getCellRange(ClastRow).setFormula(SUM(C2:C13));sheet.getCellRange(DlastRow).setFormula(SUM(D2:D13));sheet.getCellRange(ElastRow).setFormula(AVERAGE(E2:E13));// 4. 设置格式sheet.getAllocatedRange().autoFitColumns();sheet.getCellRange(A1:E1).getCellStyle().getExcelFont().isBold(true);workbook.saveToFile(monthly_report.xlsx,ExcelVersion.Version2013);这样一个完整的报表就生成了所有计算都是通过公式完成的后续修改原始数据结果会自动更新。小结总结一下几个关键点简单公式直接用setFormula()跟Excel里写法一致跨表引用用SheetName!CellAddress格式数组公式用setFormulaArray()记得调用calculateAllValue()只要计算结果不要公式遍历单元格转换直接计算公式值用calculateFormulaValue()不用创建文件新函数如位运算、URL编码等注意Excel版本兼容性实际使用中最重要的是理解业务需求选择合适的公式类型。不是所有场景都需要复杂的公式有时候简单的SUM、IF就能解决问题。希望这些经验对大家有帮助如果有其他好用的技巧欢迎交流
http://www.gsyq.cn/news/1353420.html

相关文章:

  • 2026年人工智能最新发展趋势全景解读
  • 这9个Linux命令非常危险 请大家慎用
  • linux学习笔记之linux文件管理
  • Unity音频可视化实战:从频谱分析到酷狗级动态UI
  • 基于RISC-V的家庭云方案:从硬件定制到数据安全的私有NAS实践
  • RAG + Agent = 王炸组合:知识增强型Agent详解
  • 昇腾CANN asc-tools:NPU 运维诊断工具的实战手册
  • 6 种简单方法教你如何将电脑上的音乐传输到 Redmi 手机
  • 从显卡到SSD:拆解你电脑里的PCIe设备,看懂BDF编号和Type0/Type1配置头
  • [开源] 交班信息一致性校验系统:面向临床医护的实时语义冲突检测与结构化摘要生成
  • 深入RTKLIB PPP的EKF心脏:手撕filter.c,图解扩展卡尔曼滤波的状态更新与协方差传递
  • 2026 AI x Web3 School共学营笔记-Day5
  • 快速上手:ClaudeCode安装全攻略
  • tcpdump 核心选项与过滤表达式实战指南:从基础到高效网络排查
  • CT影像数据集实战指南:临床真实性与AI可解释性
  • 手把手教你给STM32智能小车装上‘眼睛’:TSL1401线性CCD模块从接线到PID调参全流程
  • 告别数据丢失!用Arduino和AT24C256 EEPROM做个断电也能记住的密码锁
  • 别再只点灯了!用ESP8266+Blinker解锁更多玩法:温湿度监控、智能插座与消息推送
  • 贝叶斯数据草图在变系数回归模型中的应用与优化
  • STM32H743的SDRAM(W9825G6KH)性能调优与稳定性测试指南
  • 2026年4月马桶步进电机直销厂家推荐,油门电机/35byj412永磁步进电机,马桶步进电机企业怎么选择 - 品牌推荐师
  • JMeter集成Dubbo压测插件开发实战指南
  • HC-05蓝牙模块连接Arduino/STM32的实战避坑指南:从3.3V/5V电平匹配到手机APP调试全流程
  • TI C2000 DSP开发笔记:除了IQMath,F28377D的定点计算还有这些隐藏技巧(含FFT/FIR函数初探)
  • Qt侧边栏开发避坑指南:QStackedWidget页面管理、布局边距清零与QSS样式继承那些事儿
  • 2026年黑龙江纸质包装定制厂家推荐:纸箱包装/礼盒包装/食品包装/药品包装/红酒包装/月饼包装/粽子包装/特产包装/选择指南 - 海棠依旧大
  • 告别GPIO模拟!在Vivado 2023.1中快速配置Axi IIC IP核与PYNQ联调指南
  • Linux服务器CPU压力测试实战:从工具选型到性能调优
  • Godot MCP协议实战:构建游戏与AI的双向状态同步层
  • K-means空间聚类实战:从地理特征构建到城市治理落地