无法在“finally”子句中关闭流,未初始化的变量/未处理的 IOException [Java IO]

huangapple go评论88阅读模式
英文:

Cannot close() stream in 'finally' clause, uninitialized variable/unhandled IOException [Java IO]

问题

以下是翻译好的部分:

我有一个在类文件中的方法,尝试将一个 Book 对象写入到路径 aPath(字符串)中。
然而,它给了我一个“未处理的 IOException”错误,我不太确定为什么会这样,因为在 try 块中似乎已经有了 catch 子句。

为了解决这个问题,我尝试在我的方法中添加一个“throws”子句,但是一旦我这样做了,它就说“out”变量没有被初始化。

有没有办法我可以在 finally 子句中关闭我的流?

public void writeToFile(String aPath) {

    ObjectOutputStream out;
    try {
        out = new ObjectOutputStream(new FileOutputStream(aPath));

        out.writeObject(this.book);
    }
    catch(IOException e){
        System.out.println("写入文件时出错");
        e.printStackTrace();
    }
    finally {
        out.close(); // 未处理的 IOException 错误 :(
    }
}
英文:

So I have this method in a class file just trying to write a Book object to aPath (string).
However, it gives me 'Unhandled IOException', which I am not sure I understand why as it seems I have a catch clause for my try block.

So to fix this, I tried adding a 'throws' clause to my method, however once I did that, it said that the 'out' variable was not initialized.

Is there any way I can close my stream inside the finally clause?

	public void writeToFile(String aPath) {
	
		ObjectOutputStream out;
		try {
			out = new ObjectOutputStream(new FileOutputStream(aPath));
			
			out.writeObject(this.book);
		}
		catch(IOException e){
			System.out.println("Error writing to file");
			e.printStackTrace();
		}
		finally {
			out.close(); //unhandled IOException error :(
		}
	}

答案1

得分: 3

使用try with resources会处理未初始化资源的问题:

public void writeToFile(String aPath) {
    try (ObjectOutputStream out = 
             new ObjectOutputStream(new FileOutputStream(aPath))) {
        out.writeObject(this.book);
    }
    catch (IOException e) {
        System.out.println("写入文件错误");
        e.printStackTrace();
    }
}

根据JLS的规定,由writeObject调用或资源的隐式close()引发的IOException将被捕获在该处理程序中。

这是如此优雅...


关于您的尝试:

> 我想知道为什么我不能在finally子句中使用out.close()。

因为out可能尚未初始化。例如,如果IOException是在new FileOutputStream(...)中引发的,out将未被初始化。要通过显式的finally使其工作,您需要像这样做:

public void writeToFile(String aPath) {
    ObjectOutputStream out = null;
    try {
        out = new ObjectOutputStream(new FileOutputStream(aPath));
        out.writeObject(this.book);
    }
    catch (IOException e) {
        System.out.println("打开或写入文件时出错");
        e.printStackTrace();
    }
    finally {
        if (out != null) {
            try {
                out.close();
            }
            catch (IOException e) {
                System.out.println("关闭文件时出错");
                e.printStackTrace();
            }
        }
    }
}

既然您提问了... 异常处理/抑制可能是一个不好的主意:

  • 调用者无法得知文件写入失败。它将继续执行,就好像什么都没有发生。

  • 堆栈跟踪通常不应写入标准输出。如果它是相关的,堆栈跟踪应该被记录:

    • 如果这是一个面向终端用户的应用程序,向用户显示堆栈跟踪是不友好的。他们需要的是一个信息丰富的错误消息。将异常/堆栈跟踪单独记录到日志文件中,对于安装/配置软件的系统管理员或编写软件的程序员可能是有用的。
    • 如果这是一个服务,那么写入标准输出的内容可能会丢失。真正的错误应该被记录。那些(可能)是由于用户输入错误导致的问题,(可能)不应该被记录。
英文:

Using try with resources will handle the problem of uninitialized resources:

public void writeToFile(String aPath) {
    try (ObjectOutputStream out = 
             new ObjectOutputStream(new FileOutputStream(aPath))) {
        out.writeObject(this.book);
    }
    catch (IOException e) {
        System.out.println("Error writing to file");
        e.printStackTrace();
    }
}

According to the JLS, an IOException thrown by the writeObject call, OR by the implicit close() of the resource will be caught in that handler.

It is so elegant ...


Regarding, your attempt:

> I want to know why I cannot use out.close() in finally clause.

Because out has not necessarily been initialized. For example, if the IOException was thrown in new FileOutputStream(...), out won't have been initialized. To get it to work using an explicit finally, you would need to do something like this:

public void writeToFile(String aPath) {
    ObjectOutputStream out = null;
    try {
        out = new ObjectOutputStream(new FileOutputStream(aPath));
        out.writeObject(this.book);
    }
    catch (IOException e) {
        System.out.println("Error opening or writing to file");
        e.printStackTrace();
    }
    finally {
        if (out != null) {
            try {
                out.close();
            }
            catch (IOException e) {
                System.out.println("Error closing file");
                e.printStackTrace();
            }
        }
    }
}

Since you asked .... the exception handling / squashing is probably a bad idea:

  • The caller gets no indication file write has failed. It will continue executing as if nothing happened.

  • A stacktrace should not normally be written to stdout. If it is relevant, the stacktrace should be logged:

    • If this is an end-user application, showing stacktraces to users is nasty. What they need is an informative error message. Separately logging the exception / stacktrace to a log file may be useful for the sysadmin who installed / configured the software, or the programmer who wrote it.
    • If this is a service, then stuff written to standard output may be lost. Real errors should be logged. Things that are (maybe) due to bad user input should (maybe) not be logged.

huangapple
  • 本文由 发表于 2020年7月23日 09:41:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/63045588.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定