Varun
Varun

Reputation: 3311

How does the compiler know about exceptions to be thrown before execution?

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

Answers (10)

Petr Mensik
Petr Mensik

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

Mikhail
Mikhail

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

Santosh Jagannath
Santosh Jagannath

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

Dancrumb
Dancrumb

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

Sotirios Delimanolis
Sotirios Delimanolis

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

Nicola Musatti
Nicola Musatti

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

sp00m
sp00m

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

MD Sayem Ahmed
MD Sayem Ahmed

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

Maroun
Maroun

Reputation: 95968

catch(FileNotFoundException e) this line is unreachable. Since:

FileNotFoundException extends Exception

See Exception and FileNotFoundException:

enter image description here

You probably want to switch their order.

Upvotes: 10

Andy Thomas
Andy Thomas

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

Related Questions