Reputation: 3311
import java.io.*;
class ex3
{
public static void main(String args[])
{
myfun();
}
static void myfun()
{
try
{
FileInputStream f = new FileInputStream("file.ytxt");
System.out.println("my fun");
}
catch(Exception e) //Line 1
{
System.out.println(e.getMessage());
}
catch(FileNotFoundException e) //Line 2
{
System.out.println("File Not Found Caught");
}
}
}
I have created two exceptions handler code (one generic and another specific in Line 1 and Line 2).
My compiler is complaining
ex3.java:24: error: exception FileNotFoundException has already been caught
catch(FileNotFoundException e)
^
1 error
My question is how did the compiler know that "FileNotFoundException" will be thrown by the try block ?
Upvotes: 3
Views: 2071
Reputation: 27496
Your problem lies somewhere else. FileNotFoundException
will be always caught in the Exception
because this is a base class for all exceptions. So compiler basically complains about piece of dead code which is
catch(FileNotFoundException e) {
System.out.println("File Not Found Caught");
}
Generally, it is not a good idea to catch Exception
, you should always try to have more fine-grained expcetion handling, so delete this and just leave there FileNotFoundException
block
Upvotes: 6
Reputation: 4223
Java Virtual Machine Specification: Exceptions
Each method in the Java Virtual Machine may be associated with zero or more exception handlers. An exception handler specifies the range of offsets into the Java Virtual Machine code implementing the method for which the exception handler is active, describes the type of exception that the exception handler is able to handle, and specifies the location of the code that is to handle that exception. An exception matches an exception handler if the offset of the instruction that caused the exception is in the range of offsets of the exception handler and the exception type is the same class as or a subclass of the class of exception that the exception handler handles. When an exception is thrown, the Java Virtual Machine searches for a matching exception handler in the current method. If a matching exception handler is found, the system branches to the exception handling code specified by the matched handler.
The order in which the exception handlers of a method are searched for a match is important. Within a class file, the exception handlers for each method are stored in a table (§4.7.3). At run time, when an exception is thrown, the Java Virtual Machine searches the exception handlers of the current method in the order that they appear in the corresponding exception handler table in the class file, starting from the beginning of that table.
If JDK compiles such code FileNotFoundException block will be unreachable. Because of exception object is checked against instanceof
, it will always fall into first Exception block. For your case correct table will be:
Exception table:
from to target type
0 18 21 Class java/io/FileNotFoundException
0 18 33 Class java/lang/Exception
where from
and to
are instruction numbers. The table is searched top down.
Upvotes: 0
Reputation: 31
catch(Exception e)
{
System.out.println(e.getMessage());
}
catch(FileNotFoundException e)
{
System.out.println("File Not Found Caught");
}
Exception is a super class of all the exceptions.
So if we are using catch(Exception e){} then it can catch all the type of exceptions.
So the catch(FileNotFoundExecption f){} will be not reachable, so the compiler will give an error that its already been caught.
This is the correct way to write it:
catch(FileNotFoundException e)
{
System.out.println("File Not Found Caught");
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
Upvotes: 1
Reputation: 27539
There are a couple of things at play here.
First, the compiler know that a FileNotFoundException
could be thrown, because of the method signature of the FileInputStream
constructor. From the docs:
public FileInputStream(String name) throws FileNotFoundException
Thus, the signature tells the compiler that it could throw FileNotFoundException
.
However, in this instance, that information is actually immaterial because of the ordering of your catch
blocks. You have:
catch(Exception e) { /* ... */ }
catch(FileNotFoundException e) { /* ... */ }
The way catch
blocks work, if an exception is thrown in a try
block, execution goes through each cacth
block and looks to see if the type of exception in the catch
block is a polymorphic match for the thrown exception. Since FileNotFoundException
is descended from Exception
(see here), it matches the first block and always will. Thus, the second block is unreachable.
So, even if the compiler did not know that a FileNotFoundException
could be thrown, it could still infer that the second catch
block is unreachable, because any FileNotFoundException
thrown would always be caught by the first.
When defining catch
blocks, always put them in order of most specific to least, to avoid this problem.
Upvotes: 2
Reputation: 279960
To answer
My question is how did the compiler know that "FileNotFoundException" will be thrown by the try block?
You need to look at the constructor for FileInputStream
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
Notice it throws FileNotFoundException
. This declaration tells the compiler that a FileNotFoundException
is possibly thrown so make sure to handle it with a try-catch
block or let it bubble up on the method stack with another throws
clause.
As for the error you are getting, look at all the other answers.
Upvotes: 2
Reputation: 18218
A catch block will intercept exceptions of the specified class and all its subclasses. As other mentioned FileNotFoundException
is a subclass of Exception
and so it will be caught by the
catch (Exception e)
clause.
Upvotes: 0
Reputation: 48817
This isn't the point: catch(Exception e)
will catch any Exception
, i.e. FileNotFoundException
too. Catching FileNotFoundException
at a second time is thus useless.
Catch first FileNotFoundException
, then Exception
.
Upvotes: 0
Reputation: 29166
Change this -
catch(Exception e) //Line 1
{
System.out.println(e.getMessage());
}
catch(FileNotFoundException e) //Line 2
{
System.out.println("File Not Found Caught");
}
to this -
catch(FileNotFoundException e) //Line 1
{
System.out.println(e.getMessage());
}
catch(Exception e) //Line 2
{
System.out.println("File Not Found Caught");
}
Exception
is a super type of all the exception classes in Java. So, any exception object can be assigned to a reference of type Exception
. When an exception occurs in your program, catch blocks are examined sequentially from top to bottom to find a match between the type of exception occurred and the type of the exception that the catch
block is handling. As a result, any type of exceptions generated within your try block will always find the first catch block as a match and the second catch block can never be reached from your code. This is exactly why the compiler is complaining.
Upvotes: 1
Reputation: 95968
catch(FileNotFoundException e)
this line is unreachable. Since:
FileNotFoundException extends Exception
See Exception and FileNotFoundException:
You probably want to switch their order.
Upvotes: 10
Reputation: 86411
Your compiler can see that this exception would already be caught by the previous catch block.
When you catch Exception
, it also catches any subclass of Exception, such as FileNotFoundException
.
Swap the order of the catch blocks to this:
catch(FileNotFoundException e) //Line 2
{
System.out.println("File Not Found Caught");
}
catch(Exception e) //Line 1
{
System.out.println(e.getMessage());
}
Upvotes: 4