简体   繁体   中英

Throwing both main exception and sub-type, is there a proper way?

Okay, so I have a bunch of exception related questions across SO and Programmers, but there's just so much to ask, and either I don't know what to type, or not that many people have asked.

So, let's say I have a method that throws a FileNotFoundException (FNFE). I then have another method that uses the first one, but also throws a IOException (IOE).

My handler would catch both and do different things with each, but my IDE (IntelliJ) is signaling I have "a more general exception, 'java.io.IOException', in the throws list already".

I know it works if I do this:

public File openOrCreate(String pathStr) throws FileNotFoundException,
                                                IOException {
    try {

        // Method that generates the FNFE
        Path path = ReposioryProposition.getPath(pathStr);
        File file = path.toFile();

    catch (FileNotFoundException fnfe) {
        throw fnfe;
    }

    if (!file.exists())
        file.createNewFile();  // IOE
    return file;

}

But do I need to do it explicitly? Will it work without, or more dangerously, will sometimes work without the explicit version.

To make sure we are on the same page, this is how I initially wrote the thing:

public File openOrCreate(String pathStr) throws FileNotFoundException,
                                                IOException {

    Path path = ReposioryProposition.getPath(pathStr);
    File file = path.toFile();

    if (!file.exists())
        file.createNewFile();
    return file;

}

But I am unsure what happens, is the FNFE thrown or swallowed up ? My intention is to catch them separately and do different stuff for one over the other.

You only have to include the more general exception in your throws list. This already specifies that the method may throw any subclass of this exception.

In particular, you must handle the more general exception anyway, and this exception handler will also handle the subclass. If you want to handle the subclass explicitly, you have to catch it before the more general exception:

try {
    ...
} 
catch (FileNotFoundException e) {
    // handle subclass
}
catch (IOException e) {
    // handle general exception (this will not be executed if the
    // exception is actually a FileNotFoundException
} 

It's perfectly fine to omit the FileNotFoundException from the throws clause if you already have IOException in it.

Doing so doesn't affect the behaviour at all. FileNotFoundException will still be thrown, and you can catch it explicitly (as well as also having a different, more general, catch of IOException).

Having IOException in the throws clause simply states that IOException or any of its subclasses will be thrown from this method. FileNotFoundException is included in that.

But do I need to do it explicitly? Will it work without, or more dangerously, will sometimes work without the explicit version.

Yes. You have to do it explicitly, because it is a checked exception.


Directly throwing back the exception: If you just add those checked exception to your methods signature, meaning if you add throws clause in method heading like throws IOException , then you need not to catch anywhere in your method.

But doing this has one flaw, If you are accessing n files line by line in your code and each line may throw IOException, if the exception is raised. You must close the file .close() before throwing it back to the called method. So using only this throws clause will not let you to do it.

So, just catch the exception and do necessary action either in catch or finally block .

Only if no action is needed from your side and also if you want the exception to be popped out to the called method and the called method handles it, only then add the throws signature to the method.

Here is what Java Language Specification has to say :

If the run-time type of V is assignment compatible with (§5.2) a catchable exception class of any catch clause of the try statement, then the first (leftmost) such catch clause is selected . The value V is assigned to the parameter of the selected catch clause, and the Block of that catch clause is executed, and then there is a choice: ...

(Emphasis and ellipsis mine).

Therefore, if you want your more specific catch clause to be executed, you have to place it first in the catch list.

you can catch first the sub class exception if not, then the general exception class like this

try{
      // something
   } catch(FileNotFoundException fne){
      // Handle the exception here
   } catch(IOException ioe) {
      // Handle the IOException here
   }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM