Question

I can "fix" the below exception with a try-catch loop but I cannot understand the reason.

  1. Why does the part "in.readLine()" continuosly ignite IOExceptions?
  2. What is really the purpose of throwing such exceptions, the goal probably not just more side effects?

Code and 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);
  }
 }
}
Was it helpful?

Solution

The basic idea is that a BufferedReader delegates to a different kind of Reader, so it is passing on that exception.

That different kind of Reader can read from some kind of volatile external resource, say a file system in the case of FileReader. A file system read can fail for many reasons at any time. (The situation is worse if the Reader is getting its underlying data from a Network Stream). The file could get deleted out from under you (depending on the file system and OS involved).

Because you cannot predict what will happen with code, you get a checked exception - the point being that the API is telling you that you should think about the fact that this operation may not work out even if there is nothing wrong with your code.

OTHER TIPS

  1. It won't "continously ignite" them, it just might throw them each time you invoke it. In your case, if it throws something it means something has gone badly wrong with your standard input.
  2. The goal is to ensure that you, the programmer using the API, deals with the problem, since it is in general assumed to be a recoverable problem - although in your particular case it will be fatal for your whole program.

BufferedReader.readLine() is declared as potentially throwing an exception, see: http://java.sun.com/j2se/1.3/docs/api/java/io/BufferedReader.html#readLine()

You either need to catch it, or declare your main method as throwing IOException.

Ie, either do this:

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

Or

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

IOException is a checked exception. You must either catch it, or throw it to your calling method. Checked exceptions are caused by external actors, like a missing file, failed disk or anything that you cannot recover from in your program code.

However an Unchecked exception like ArrayIndexOutofBoundsException is caused by faulty logic in the program. You can subvert it by using an if condition outside your defective code (something like if currIndex>array.length). There is no such provision in case of checked exception

It is thrown if an exceptional situation occurs with the I/O, for example the source of the stream is no longer available.

In such cases your program should be able to recover. Either by re-reading the source, or by using some defaults, or by alerting the user about the problem.

You are forced to catch it, because it is a checked exception, and you are supposed to be able to recover from those.

Of course, you have the option to declare that the current menthod throws this exception to caller methods, but you will have to catch it eventually (or let it bubble up to the main method, when it is simply printed on the console and the program execution stops)

Using Scanner for reading files (or other type of input) can be extremely inefficient in mid/large scale situations. If you have performance concerns reading thousands or milions of lines, i strongly recommend you use BufferedReader class instead. An example of usage of BufferedReader to read lines from System.in is displayed below:

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 should be used in try/catch block so can be triggered whenever the protected code inside try suffers of an "exceptional" behavior such as an error. Java has his own Exceptions that are throwned when similar situation happen. For example, ArrayIndexOutOfBoundsException is throwned when you define an array a of size n and you try to access the position a[n+1] somewhere in your code. As ArrayIndexOutOfBoundsException, there are many other Exception classes you can throw and customize with your own messages. The code suitable to an exception should be placed in the protected zone in try block. When the exception occurs in that block, the exception will be handled in catch block with it.

Look that you don't need to build if/else statements to anticipate the error situation and throw an Exception for each case. You just need to associate possible Exception situations between try and catch block. See more about try/catch blocks is encouraged for safe programming.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top