我知道如何通过if / else检查文件是否存在,并且它在我之前的任务中有效:
File f = new File("file.txt");
if (f.exists() && f.canRead()) {
// Code goes here.
} else { } // Error message.
但是,如果我对缓冲图像执行相同的操作,请执行以下操作:
private BufferedImage img;
File f = new File("pic.png");
if (f.exists() && f.canRead()) {
img = ImageIO.read(f);
} else { } // Error message.
然后编译器需要try / catch或@throws来破坏目的。我究竟做错了什么?将所有精灵打包成一个.jar并将它们称为资源(我计划在完成后再做)会不会更好?
如果有任何问题,我在JRE 1.6上运行,文件检查在switch case语句中。
答案 0 :(得分:2)
作为一个经过检查的例外,您必须抓住它。它实际上是否抛出并不重要。您的手动错误处理将无法处理所有情况。考虑您正在从网络驱动器读取,并且在读取时可能会中断连接。
更新查看上面的评论。据说你必须构建一个try / catch块,因为可以抛出异常并处理每个指定所需的已检查异常。通过先前的检查,您已经避免了FileNotFoundException
的风险。有时你甚至让我对实现没有任何错误的地方进行了分类,但是在接口中你还需要处理它,例如ByteArryOutputStream.close()
答案 1 :(得分:2)
使用 try / catch块并不会破坏目的。
即使该文件存在且可读,也有很多其他异常可以抛出。
可能的例子:
方法ImageIO.read()会抛出IOException。
没有办法避免捕捉或抛弃它。
答案 2 :(得分:2)
我们已经与他详细讨论了这个问题,他说的是,如果我确切地知道将要发生什么,我应该尝试处理它而不诉诸尝试/捕获后退。
如果你的导师告诉你应该测试以避免IO异常,那么我担心他完全错了。
大多数I / O操作被声明为throw IOException
,这是一个经过检查的异常。当您调用这些方法时,您的代码必须处理或传播异常。你没有选择。 Java语言要求对所有已检查的异常执行此操作。
测试所有可能的IOExceptions是不切实际的。例如,此代码可能会失败:
if (f.exists() && f.canRead()) {
os = new FileInputStream(f);
}
为什么呢?因为构造函数可能抛出IOException还有其他原因,例如硬盘错误,网络错误(如果文件位于远程安装的文件系统上),强制访问控制失败等等。除了尝试打开文件之外,通常无法以任何其他方式检测基础条件。
然后是竞争条件的问题。在上面的示例中,测试文件可读并尝试打开它之间有一个小的时间窗口。在该时间窗口中,可能某个其他线程或某个外部进程将删除该文件或更改其访问权限,以便打开将失败。无法关闭该时间窗口。
然后有一个问题,为什么你甚至想要来避免异常。我怀疑你的老师是“例外人”;也就是那些把“例外只应用于特殊事物”的建议中的一个人提到不合逻辑的极端。
“异常只应用于特殊事物”建议基本上是说你不应该过度使用异常,因为它们有点贵。但昂贵是相对的。
在此示例中,对File.exists()
和File.canRead()
的调用也很昂贵,因为它们都需要进行系统调用,这将花费数千个时钟周期。更糟糕的是,除非您的应用程序有一些不寻常的事情,否则这两个测试将会成功...所以您刚刚完成了两次不必要的系统调用,以避免无论如何都不会抛出异常。除非这些测试失败的概率很高(即> 50%),否则跳过测试更高效,尝试打开并处理异常(如果发生)。
我不会这样标记我的教授。我们没有具体谈论I / O的复杂性,它更多地是在一般的术语中,如果我可以避免它,我应该避免它。我不知道(并且他没有详细说明)有一些非常不可避免的异常。
行。所以你的教授没有这么说。对他有好处。
是的,他们在某种意义上不可避免地。
至于拒绝使用.exists()检查,性能是否显着?
是。见这 - Syscall overhead
或者,如果你不相信,那就写一个微基准并测量它。并将其与投掷和捕获异常的开销进行比较。
是否会出现桌面版移动版等问题?
不。或者当然不适用于操作系统使用虚拟内存来阻止一个“app”干扰另一个“app”的移动设备。
对于故障排除/调试(如果我能够更好地查明问题,同时避免崩溃程序)的清晰度是否值得呢?
好吧,我认为这段代码:
try (InputStream is = new FileInputStream(f)) {
// use file
} catch (IOException ex) {
System.err.println("IO error: ": ex.getMessage());
}
...比这更简单,更容易维护和调试:
if (!f.exists()) {
System.err.println("File " + f + " does not exist");
} else if (!f.isDirectory()) {
System.err.println("File " + f + " is a directory");
} else if (!f.canRead()) {
System.err.println("File " + f + " is not readable");
} ...
} else {
try (InputStream is = new FileInputStream(f)) {
// read
} catch (IOException ex) {
System.err.println("IO error: "+ ex.getMessage());
}
}
你不同意吗?
答案 3 :(得分:1)
如果您看到ImageIO.read
方法的声明: -
public static BufferedImage read(File input)
throws IOException
它声明要抛出IOException
,这是CheckedException
。因此,在调用该方法时,您需要在try-catch block
中处理它。或者,声明它将在您使用它的方法中抛出: -
File f = new File("pic.png");
if (f.exists() && f.canRead()) {
try {
img = ImageIO.read(f);
} catch (IOException e) {
e.printStackTrace();
}
} else { } // Error message.
但是,如果您没有像上面那样处理它,那么您必须在方法的throws
子句中声明该方法,以便将其传播到caller
,所以它处理它。
通常,任何已检查的异常都应该被处理或传播给调用者,后者逐渐达到main
方法,在这种情况下,如果main
方法不处理它,则由JVM
,导致您的计划终止。
通常,在抛出它的方法本身中处理异常是个好主意,并在需要时将相应的消息返回给调用者。