团队成员在使用以下代码时遇到了麻烦:
void extractData(String targetUri) { Path tempFile = createTempFilePath(); extractDataToPathAndUpload(tempFile, targetUri); cleanUp(tempFile); } void extractDataToPathAndUpload(Path tempFile, String targetUri) { try (FileOutputStream stream = createOutput(tempFile)) { // extract from db to file stream database.readTable(TABLE_1, stream); // upload the temp file to the destination uploader.upload(tempFile, targetUri); } }
上面的代码经过精简和简化,使您对问题有所了解。 我们有一个数据库,一个要写入的临时临时文件和一个上载过程。
问题是上upload
呼叫无法正常工作。 真令人沮丧!
老鹰眼的读者可能会发现,在进行上upload
调用时,由第二个函数内的OutputStream
写入的临时文件尚未关闭。 那是个错误,解决方法是将调用upload
到try-with-resources块之外,该块的工作是关闭流,从而释放文件(至少在Windows上,您不能读取您也在写的文件!)。
错误不是那样!
这是一个很难发现的错误,是结构决策的结果。 上载调用属于导出操作之外的原因不仅是为了确保流关闭,还因为它是整个过程的另一个阶段。 该过程应该是:
- 创建临时位置
- 导出到临时位置
- 清理临时位置
这里的缩进反映了作用域。
上面的实现合并了两个中间步骤,甚至似乎将导出操作置于导出中。 这是一个结构性错误。
有一个论点是,上面的代码应该被编写为三个函数,而不是两个:
- 一种功能,用于管理临时文件,然后调用...
- 下一个调用导出,然后上传的函数
- 导出功能
这是一个很好的例子,说明在正确使用结构方面的一些额外精度将减少难于发现的错误将我们赶走的可能性。
翻译自: https://www.javacodegeeks.com/2019/10/the-structural-bug.html