如何在forEach中复用被调用函数返回值实现PDF链式处理
解决方法:用Stream.reduce替代forEach实现迭代更新
你当前的代码问题在于,forEach是无状态的循环——每次调用addToPdf时,传入的都是最初的decoratedDataAsByte,所有附件都是直接加到原始PDF上,而不是依次叠加。最后返回的还是原始字节数组,完全没用到每次生成的新PDF结果。
要实现“把上一次生成的新PDF作为下一次的输入”,你需要用Stream的reduce方法,它专门用来处理这种累加式的迭代逻辑——可以把前一步的输出作为后一步的输入,逐步更新结果。
修改后的代码
public byte[] doDecoration(byte[] decoratedDataAsByte, RendererConfiguration config, List<IReadonlyPersistedAttachment> pdfAttachments) { // 使用reduce迭代处理每个附件,逐步更新PDF return pdfAttachments.stream() .reduce(decoratedDataAsByte, (currentPdf, att) -> addToPdf(config, att, currentPdf), (pdf1, pdf2) -> pdf1); // 并行流才会用到,串行场景下可以忽略,这里保持语法完整 } private byte[] addToPdf(RendererConfiguration config, IReadonlyPersistedAttachment att, byte[] decoratedDataAsByte) { byte[] addedPdf = decoratedDataAsByte; if (config.getAddPdfAtBegin().contains(att.getAttName())){ addedPdf = PdfUtils.addPdfAtBegin(decoratedDataAsByte, att.getBinary().getBinaryData()); } else if (config.getAddPdfAtEnd().contains(att.getAttName())){ addedPdf = PdfUtils.addPdfAtEnd(decoratedDataAsByte, att.getBinary().getBinaryData()); } else{ addedPdf = PdfUtils.addPdfAtEnd(decoratedDataAsByte, att.getBinary().getBinaryData()); } return addedPdf; }
代码说明
reduce的工作逻辑:
- 第一个参数
decoratedDataAsByte是初始值,也就是第一次处理时的输入PDF。 - 第二个参数是累加器函数:每次用当前已经处理好的PDF(
currentPdf)和下一个附件(att)调用addToPdf,得到新的PDF字节数组,作为下一次迭代的输入。 - 第三个参数是合并函数,只有在并行流场景下才需要用来合并不同线程的结果,这里我们用串行流,所以直接返回第一个参数即可。
- 第一个参数
额外优化点:
你的addToPdf里的else分支和第二个else if逻辑重复,可以简化一下:private byte[] addToPdf(RendererConfiguration config, IReadonlyPersistedAttachment att, byte[] decoratedDataAsByte) { if (config.getAddPdfAtBegin().contains(att.getAttName())){ return PdfUtils.addPdfAtBegin(decoratedDataAsByte, att.getBinary().getBinaryData()); } // 剩下的情况都加到末尾,不用重复写逻辑 return PdfUtils.addPdfAtEnd(decoratedDataAsByte, att.getBinary().getBinaryData()); }
这样修改后,每个附件都会依次叠加到前一次生成的PDF上,最终返回的就是处理完所有附件的最终PDF字节数组了。
内容的提问来源于stack exchange,提问作者Al Phaba
相关产品推荐
相关产品推荐

