10

我可以使用 try-catch 循环“修复”以下异常,但我无法理解原因。

  1. 为什么“in.readLine()”部分会持续引发 IOExceptions?
  2. 抛出此类异常的真正目的是什么,目标可能不仅仅是更多的副作用?

代码和 IOExceptions

$ javac ReadLineTest.java 
ReadLineTest.java:9: unreported exception java.io.IOException; must be caught or declared to be thrown
  while((s=in.readLine())!=null){
                      ^
1 error
$ cat ReadLineTest.java 
import java.io.*;
import java.util.*;

public class ReadLineTest {
 public static void main(String[] args) {
  String s;
  BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
  // WHY IOException here?
  while((s=in.readLine())!=null){
   System.out.println(s);
  }
 }
}
4

6 回答 6

11

基本思想是 BufferedReader 委托给不同类型的 Reader,因此它传递了该异常。

这种不同类型的 Reader 可以从某种易失的外部资源中读取,例如 FileReader 中的文件系统。文件系统读取在任何时候都可能由于多种原因而失败。(如果阅读器从网络流中获取其基础数据,情况会更糟)。该文件可能会从您下方删除(取决于所涉及的文件系统和操作系统)。

因为您无法预测代码会发生什么,所以您会得到一个已检查的异常 - 关键是 API 告诉您应该考虑这样一个事实,即即使您的代码没有任何问题,此操作也可能无法执行。

于 2010-04-13T13:11:03.703 回答
3

BufferedReader.readLine()被声明为可能引发异常,请参阅:https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/BufferedReader.html#readLine()

您要么需要捕获它,要么将您的主要方法声明为抛出 IOException。

即,要么这样做:

try {
    while((s=in.readLine()) != null){
        System.out.println(s);
     }
} catch(IOException e) {
    // Code to handle the exception.
}

或者

public static void main(String[] args) throws IOException { ...
于 2010-04-13T13:05:28.430 回答
3
  1. 它不会“持续点燃”它们,它可能会在您每次调用它时抛出它们。在您的情况下,如果它抛出一些东西,则意味着您的标准输入出现了严重错误。
  2. 目标是确保您(使用 API 的程序员)处理该问题,因为它通常被认为是可恢复的问题 - 尽管在您的特定情况下它对您的整个程序来说是致命的。
于 2010-04-13T13:05:37.193 回答
1

IOException 是一个检查异常。你必须要么抓住它,要么把它扔给你的调用方法。已检查的异常是由外部参与者引起的,例如丢失的文件、故障的磁盘或您在程序代码中无法恢复的任何内容。

但是,像 ArrayIndexOutofBoundsException 这样的未经检查的异常是由程序中的错误逻辑引起的。您可以通过在有缺陷的代码之外使用 if 条件来颠覆它(例如 if currIndex>array.length)。在检查异常的情况下没有这样的规定

于 2010-04-13T13:01:57.560 回答
1

如果 I/O 发生异常情况,例如流的源不再可用,则抛出它。

在这种情况下,您的程序应该能够恢复。通过重新阅读源代码,或者使用一些默认值,或者通过警告用户问题来实现。

你被迫这样catch做,因为它是一个检查异常,你应该能够从中恢复。

当然,您可以选择声明当前方法throws将此异常传递给调用方方法,但您最终必须捕获它(或者让它冒泡到 main 方法,当它只是在控制台上打印并执行程序时停止)

于 2010-04-13T13:03:49.177 回答
1

用于Scanner读取文件(或其他类型的输入)在中/大规模情况下效率极低。如果您在阅读数千或数百万行时有性能问题,我强烈建议您改用BufferedReader类。System.in下面显示了使用 BufferedReader 读取行的示例:

public static void main(String[] args) throws Exception {

    String line = null;
    BufferedReader br = new BufferedReader (new InputStreamReader(System.in));

    try {
        /* This is protected code. If an problem occurs here, catch block is triggered */
        while ( (line = br.readLine()) != null ){
            System.out.println(line); 
        }
    }
    catch (IOException e){
        throw new IOException("Problem reading a line",e);
    }
}

IOException 应该在try/catch块中使用,以便在内部try受保护的代码遇到“异常”行为(例如错误)时触发。Java 有他自己的异常,当发生类似情况时会抛出这些异常。例如,ArrayIndexOutOfBoundsException当您定义一个a大小数组n并尝试访问a[n+1]代码中某处的位置时抛出。作为ArrayIndexOutOfBoundsException,还有许多其他异常类,您可以使用自己的消息抛出和自定义。适合异常的代码应该放在 try 块的保护区内。当该块中发生异常时,将在 catch 块中处理该异常。

看起来您不需要构建if/else语句来预测错误情况并为每种情况抛出异常。您只需要将可能的异常情况关联到trycatch块之间。鼓励查看有关try/catch 块的更多信息以进行安全编程。

于 2017-11-09T16:15:16.260 回答