此文已由作者叶富宏授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。

昨天一个商务反馈说报价信息导出失败,查看了一下日志发现是导出记录到Excel的时候报了NullpointException异常。报错的是下面这个方法里面,标红的代码(dataRow为null)。

private void MergedRowRegion(Sheet sheet, int endRowNum, int rowNum){        if(endRowNum > rowNum){Row dataRow = sheet.getRow(rowNum);            for(int i=0; i< 8; i++){                Cell cell = dataRow.getCell(i);if(cell != null){sheet.addMergedRegion(new CellRangeAddress(rowNum, endRowNum, i, i));}}}}

这个方法的作用是把从rowNum行到endRowNum的第1到第七列进行单元格合并。反复检查了好几遍代码和数据,除了发现数据量比较多以外,并没有发现有什么地方会造成dataRow为null的情况,通过调试终于发现了原因,现在就把这个问题记录一下。

简单说一下导出的业务:导出的信息包含商品、供应商和供应商报价。一个商品可以包含多个供应商信息,每个供应商可以有多个报价。Excel的格式如下:

所以当一个商品对应多个供应商和报价的时候,需要对商品和供应商的信息进行合并单元格。往Excel写入数据的步骤是这样的:首先在第rowNum行写入商品信息、再写入供应商信息和报价信息并对供应商信息进单元格合并,然后返回最后所在的行号endRowNum,最后把endRowNum和rowNum传入上面的方法对商品属性进行单元格合并。报异常的那个商品总共有1739条报价,量有点多。

往Excel写入数据的时候,数据会先保存在SXSSFSheet的_rows里面,_rows是一个TreeMap<Integer, SXSSFRow>,Key是行(Row)的索引,从0开始1,2,3...递增,Value是对应的行数据。通过断点发现_rows里面的数据key是从739开始的740,741,742.....一直到1739总共1000条记录。放入1739条数据,里面只有后面的1000条。通过接下去的调试发现,当_rows里面的数据大于等于1000条的时候,如果再往里面插入一条数据,size依旧是1000,但是最前面的那条数据就被挤出去了(先进先出)。

查看了一下SXSSFSheet里面createRow的方法,找到了原因,代码如下:

public SXSSFRow createRow(int rownum) {......SXSSFRow newRow = new SXSSFRow(this, initialAllocationSize);   this._rows.put(Integer.valueOf(rownum), newRow);   this.allFlushed = false;   if(this._randomAccessWindowSize >= 0 && this._rows.size() > this._randomAccessWindowSize) {   try {        this.flushRows(this._randomAccessWindowSize);} catch (IOException var7) {        throw new RuntimeException(var7);}  return newRow;......}
参数rownum是行的下标,也是_rows的key,通过代码发现创建了新的一行以后,
会调用 this.flushRows(this._randomAccessWindowSize);方法,
通过方法名就能知道应该是刷新缓存之类的作用,flushRows方法的代码如下:
public void flushRows(int remaining) throws IOException {        while(this._rows.size() > remaining) {            this.flushOneRow();}        if(remaining == 0) {            this.allFlushed = true;}}
flushOneRow方法的代码如下:
private void flushOneRow() throws IOException {
        Integer firstRowNum = (Integer)this._rows.firstKey();//取出最小的keyif(firstRowNum != null) {            int rowIndex = firstRowNum.intValue();SXSSFRow row = (SXSSFRow)this._rows.get(firstRowNum);            this._writer.writeRow(rowIndex, row);//this._rows.remove(firstRowNum);            this.lastFlushedRowNumber = rowIndex;}}

通过代码可以看到,flushOneRow方法里会取出key最小的一条数据,写入文件中,然后从_rows中删除,让_rows一直维持在1000的大小。

这就解释了为什么放入了1739条数据,_rows中只有1000条,并且存在的都是后面的。

所以当调用sheet.getRow(rowNum)去取那些从_rows删掉的数据就会返回null。

从源码中可以看到,默认情况下_rows的size是保持在100的,而非1000.

 public static final int DEFAULT_WINDOW_SIZE = 100; public SXSSFWorkbook(XSSFWorkbook workbook, int rowAccessWindowSize, boolean compressTmpFiles,
boolean useSharedStringsTable) {        this._sxFromXHash = new HashMap();        this._xFromSxHash = new HashMap();        this._randomAccessWindowSize = 100;        this._compressTmpFiles = false;        this._sharedStringSource = null;        this.setRandomAccessWindowSize(rowAccessWindowSize);        this.setCompressTempFiles(compressTmpFiles);
.......

可以通过构造函数进行修改:

public SXSSFWorkbook(int rowAccessWindowSize) {        this((XSSFWorkbook)null, rowAccessWindowSize);}

免费体验云安全(易盾)内容安全、验证码等服务

更多网易技术、产品、运营经验分享请点击。

相关文章:
【推荐】 ShimmerTextView
【推荐】 一文读懂加固apk的开发者是怎么想的

转载于:https://www.cnblogs.com/zyfd/p/9877199.html

分析自己遇到的Excel导出报NullpointException问题相关推荐

  1. Excel导出报错 You can define up to 4000 styles in a .xls workbook

    导出 Excel数据多报错:java.lang.IllegalStateException: The maximum number of cell styles was exceeded. You c ...

  2. C# Excel导出超出65536行报错 Invalid row number (65536) outside allowable range (0..65535)

    C# Excel导出超出65536行报错 Invalid row number (65536) outside allowable range (0-65535) 一:报错 Invalid row n ...

  3. 【解耦Excel导出服务】开发日志

    一.开发分析 1.导出excel设计分析 瓶颈:大量数据导出时 mysql查询连接占用时间过长 组装对象生成excel时,容易导致CPU占用过高.JVM临时内存占用过大(可能导致oom,可能导致GC) ...

  4. 从Excel导出宕机到初学Apache POI

    学习来由 因为在定位一个公司的OOM的时候,花了2天时间,定位问题定位出了方向,知道是导出Excel的时候对象占用太大导致的OOM,但是后来计算了一下数据完全没有达到OOM的情况.症结点就是结论是没错 ...

  5. php phppowerpoint 生成表格_php之EXCEL导出代码生成器的实现思路

    背景: 在实际工作中经常会遇到将数据导出到excel这样的需求,对于php语言来说导出excel也不是什么难事,因为借助phpoffice之phpspreadsheet开源库可以轻松实现.有过导出EX ...

  6. 记一次悲惨的 Excel 导出事件

    背景 话说这个背景挺惨的,京东某系统使用了poi-ooxml-3.5-final做excel导出功能.起初使用该版本的poi的HSSF配合多线程生成excel,没有任何问题,后来改成了XSSF生成后上 ...

  7. 由excel导出引起的cpu 100% 和gc 的问题

    大家好,我是烤鸭:     记一次 由excel导出 导致的cpu飙升200%,jvm 内存不足. 1.  场景复现 前端页面导出Excel,之前导出4,5W条数据都没什么问题的.     今天业务突 ...

  8. easyexcel导出百万级数据_百万级别数据Excel导出优化

    这篇文章不是标题党,下文会通过一个仿真例子分析如何优化百万级别数据Excel导出. 笔者负责维护的一个数据查询和数据导出服务是一个相对远古的单点应用,在上一次云迁移之后扩展为双节点部署,但是发现了服务 ...

  9. 根据children动态复杂表头excel导出_Java高级特性-注解:注解实现Excel导出功能

    注解是 Java 的一个高级特性,Spring 更是以注解为基础,发展出一套"注解驱动编程". 这听起来高大上,但毕竟是框架的事,我们也能用好注解吗? 的确,我们很少有机会自己写注 ...

最新文章

  1. 关于SQL命令中不等号(!=,)
  2. 教你用机器学习匹配导师 !(附代码)
  3. d.php xfso_PHP扩展调用so动态链接库
  4. 浅析响应式网站建设的注意要点
  5. Struts2返回JSON数据的具体应用范…
  6. Bzoj 3680 吊打xxx【[模拟退火】
  7. 选哪扇门得奖金的算法
  8. Mysql的一些问题
  9. spring四种依赖注入方式
  10. VMware设置及linux静态ip设置
  11. 调用高德逆地理接口_地理编码与逆地理编码
  12. 机器学习基础算法18- 鸢尾花数据集分类-随机森林
  13. Linux内核中的jiffies及其作用介绍及jiffies等相关函数详解
  14. 算法:回溯解决电话拨号中的字母组合Letter Combinations of a Phone Number
  15. python第三方模块下载方法(最详最细)
  16. win7中怎么显示文件名后缀
  17. android opengl 帧动画,Android OpenGLES2.0(十三)——流畅的播放逐帧动画
  18. 关于Http的一些基础内容
  19. 计算机打文档的技巧,电脑word文档下划线怎么打(word文档编辑小技巧)
  20. php弱口令总结,web漏洞之弱口令

热门文章

  1. mac php yaf 安装,mac下安装yaf
  2. php yaf 安装,Yaf安装与部署
  3. mui初级入门教程(一)— 小白入手mui的学习路线
  4. 横条导航窗体html代码,各式各样的导航条效果css3结合jquery代码实现
  5. 学徒浅析Android——Role带来的角色扮演
  6. 本地计算机添加网络打印机共享,手把手教你win7如何设置局域网共享打印机
  7. mysql to_day函数_mysql 日期函数to_days注意事项
  8. 微信小程序页面上面的名字怎么改_微信小程序如何动态修改页面标题——已解决...
  9. java entryset用法_entrySet如何用的。
  10. 【安路FPGA】从流水灯入门安路开发环境