5

I have the following code

public static void nocatch()
{
    try
    {
        throw new Exception();
    }
    finally
    {

    }
}

Which gives the error

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
Unhandled exception type CustomException

My Question is why was it designed that the catch block is optional, when there is no way of getting around not having a catch?


From finally()'s perspective, I understand that

finally should have atleast a try block, catch is optional. The point of finally blocks is to make sure stuff gets cleaned up whether an exception is thrown or not. As per the JLS

A finally clause ensures that the finally block is executed after the try block and any catch block that might be executed, no matter how control leaves the try block or catch block.


Edit:

By adding a return in the finally block, compiler does not give the error WHY?!

public static void nocatch()
{
    try
    {
        throw new Exception();
    }
    finally
    {
        return; //By adding this statement, the compiler error goes away! Please let me know why
    }
}
codeMan
  • 5,730
  • 3
  • 27
  • 51
  • The question as to "why" is pretty much opinion based; the fact is that Java is (as far as I know) the only language to have the notion of checked exceptions, and it appears that your `CustomException` is such an exception. And there are rules for dealing with checked exceptions. – fge Mar 04 '15 at 14:28
  • It allows you to implement the `finally` clause. It won't "hide" the exception. – Hot Licks Mar 04 '15 at 14:29
  • Going to throw try with resources (http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html) in here for omiting finally as well ;) – SBI Mar 04 '15 at 14:29
  • Doesnt matter what is a `CustomException`. For argument sake lets consider just `Exception` – codeMan Mar 04 '15 at 14:30
  • As to why there's the concept of "checked exceptions", you can blame that on a guy named Goodenough. He wrote an article on exception handling and the Java guys copied it. – Hot Licks Mar 04 '15 at 14:32
  • 1
    @HotLicks: By "blame" you do, of course, mean "give due credit and reverence for one of the outstanding features of the Java language and environment." ;-) – T.J. Crowder Mar 04 '15 at 15:15
  • @T.J.Crowder - No, I mean blame ;) – Hot Licks Mar 04 '15 at 20:49
  • [Neil's comment](https://softwareengineering.stackexchange.com/questions/131397/why-use-try-finally-without-a-catch-clause/131400#comment328505_131400) has a, practically, good example. – lupchiazoem Jun 18 '18 at 08:51

1 Answers1

14

My Question is why was it designed that the catch block is optional, when there is no way of getting around not having a catch?

Yes there is: Declare that the method throws the exception:

public static void nocatch() throws CustomException
{
    try
    {
        throw new CustomException();
    }
    finally
    {

    }
}

try/finally without catch is to ensure that you clean up anything you need to clean up, even if you aren't handling the exception yourself. (Be sure not to allow any other exception to be thrown from within finally, or you'll hide the primary exception.)

Here's an example to play with (live copy):

private static class CustomException extends Exception {
}
public static void main (String[] args) throws java.lang.Exception
{
    try
    {
        System.out.println("Calling nocatch(false)");
        nocatch(false);
    }
    catch (CustomException ce) {
        System.out.println("Caught CustomException for false case");
    }
    try
    {
        System.out.println("Calling nocatch(true)");
        nocatch(true);
    }
    catch (CustomException ce) {
        System.out.println("Caught CustomException for true case");
    }
}

public static void nocatch(boolean foo) throws CustomException
{
    try
    {
        if (foo) {
            System.out.println("Throwing");
            throw new CustomException();
        }
    }
    finally
    {
        System.out.println("In finally");
    }
    System.out.println("Reached outside the try/finally block");
}

Output:

Calling nocatch(false)
In finally
Reached outside the try/finally block
Calling nocatch(true)
Throwing
In finally
Caught CustomException for true case

As you can see, the finally block's code runs regardless of whether an exception occurred, but the code after the try/finally doesn't.


Re your follow-up asking why adding return within the finally makes the error go away:

try
{
    throw new CustomException();
}
finally
{
    return; // <=== Makes the compiler happy (but don't do it!)
}

Interesting edge case! It's because the code in the finally block always runs, and so you'll always return rather than throw, hiding the exception that occurred. E.g., this is the sequence:

  1. throw new CustomException() throws the exception, which transfers control to the finally block

  2. Code in the finally block issues a normal return from the method

This hides the fact the exception occurred; in effect, you've "handled" the exception (without actually handling it) via the finally block. In general, this isn't a good idea; use catch to handle exceptions, or declare them on the method so calling code can handle them.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • if you have a throws clause, there is no need for a try{} in the first place. But If I understand correctly, in the above case we are adding try block only to have the finally... is that right? – codeMan Mar 04 '15 at 15:11
  • 1
    @codeMan: Right: The purpose is to say "I'm going to do this stuff, which may throw an exception; whether it does or not, be sure to run my `finally` code so I can clean up afterward." Which is why the standard `try` **must** be followed by either `catch` or `finally` (or both) (try-with-resources can stand completely alone, because it has *implicit* `catch` and `finally` clauses). – T.J. Crowder Mar 04 '15 at 15:13
  • Thanks for the extra info. There is one more little thing that I cannot fathom upon.. I have edited my question, can you please take a look. – codeMan Mar 04 '15 at 15:18
  • @codeMan: Added a bit to the bottom: It's because if you do that, your method no longer throws at all. – T.J. Crowder Mar 04 '15 at 15:50