将变量初始化为null是反模式吗



摘要

我正在研究这样一个场景:

File someFile = null;
try
{
someFile = File.createTempFile( SOME_PREFIX, SOME_SUFFIX, targetDirectory );
}
catch( IOException e )
{
throw new SomeException( "Unable to create file for domain specific task", e, SomeExceptionErrorCode.FILE_MANAGEMENT_ERROR );
}

try( BufferedOutputStream stream = new BufferedOutputStream( new FileOutputStream( someFile.getAbsolutePath() ) ) )
{
stream.write( byteData, 0, byteData.length );
stream.flush();
}
catch( IOException e )
{
throw new SomeException( "Unable to write domain specific data to domain specific file", e, SomeExceptionErrorCode.FILE_MANAGEMENT_ERROR );
}

对于这种情况,CCD_ 1是用CCD_ 2初始化的。我的意图是将此代码翻译成遵循适当实践的代码。

我的想法

  • 简单地将someFile初始化为null,如当前代码片段所示。然而,我通常会避免这样做,所以到目前为止,这似乎并不令人满意
  • 初始化someFile,例如一个空的String。这提供了一个默认的File实例。我看到的问题是,如果这种错误处理在未来发生变化,那么一个具有无意义属性的有效File可能会被传递到代码中的其他位置
  • 嵌套try-someFile0块。这确实有效,但是由于某些原因感觉不好,特别是因为两个嵌套块都捕获了IOException
  • 也考虑了Optional<File>,但我不相信每个try-catch块(其中初始化了一个稍微复杂的对象以在该块之外使用)是否都证明使用Optional是合理的

问题

someFile初始化为null是反模式吗?如果是这样的话,如何最好地处理一个场景,比如发布的场景?

这样的东西怎么样:

public void yourMethod() {
File file = createFile();
writeFile(file);
}
private File createFile() {
try {
return File.createTempFile(...);
} catch(...) {
...
}
}
private void writeFile(File file) {
try(...) {
...
} catch(...) {
...
}
}

因此,您的方法保持简洁易懂。

编辑:甚至从createFile:返回Optional<File>

private Optional<File> createFile() {
try {
return Optional.of(File.createTempFile(...));
} catch(...) {
...
return Optional.empty();
}
}

然后您可以在null1:中使用Optional.ifPresent

public void yourMethod() {
Optional<File> file = createFile();
file.ifPresent(value -> writeFile(value));
// or shorter:
createFile()
.ifPresent(this::writeFile);
// depends on how exactly the methods receive their parameters
}

您可以只使用

File someFile;

没有任何显式赋值。

Java通常会抱怨在变量有值之前使用该变量,但编译器足够聪明,可以理解变量可能没有值的唯一方法是createTempFile抛出IOException,但由于您捕捉到了throw,它知道方法在这里退出,或者someFile有一个正确的值。因此,允许以后使用CCD_ 26。

这比null更干净,因为现在如果你删除了异常的重新抛出,你的代码将不再编译,因为现在编译器无法再推断总是会分配一个值。如果你用null初始化并删除重抛出,你稍后会遇到一个NPE。

这里不需要选项,因为编译器在这种情况下可以区分未初始化的值和初始化的值。

最新更新