8
static int retIntExc() throws Exception{
    int result = 1;
    try {
        result = 2;
        throw new IOException("Exception rised.");
    } catch (ArrayIndexOutOfBoundsException e) {
        System.out.println(e.getMessage());
        result = 3;
    } finally {
        return result;
    }
}

A friend of mine is a .NET developer and currently migrating to Java and he ask me the following question about this source. In theory this must throw IOException("Exception rised.") and the whole method retIntExc() must throws Exception. But nothing happens, the method returns 2.

I've not tested his example, but I think that this isn't the expected behavior.

EDIT: Thanks for all answers. Some of you have ignored the fact that method is called retIntExc, which means that this is only some test/experimental example, showing problem in throwing/catching mechanics. I didn't need 'fix', I needed explanation why this happens.

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
Kiril Kirilov
  • 11,167
  • 5
  • 49
  • 74

7 Answers7

18

This is why you can't return from a finally block in C# :)

It's absolutely the behaviour laid out in the Java Language Specification though. It's specified in section 14.20.2.

If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and the throw of value V is discarded and forgotten).

Returning is one example of completing abruptly; if the finally block threw an exception, that would also complete abruptly, losing the original exception.

The quote above was from this nested set of bullet points, leaving out the options which aren't applicable here:

  • If execution of the try block completes abruptly because of a throw of a value V, then there is a choice:
    • If the run-time type of V is not assignable to the parameter of any catch clause of the try statement, then the finally block is executed. Then there is a choice:
      • If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and the throw of value V is discarded and forgotten).
alb-i986
  • 325
  • 2
  • 14
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
3

It will return 2 because

finally always execute

2

The finally block executes no matter what exception is thrown. It doesn't just execute after the exceptions are caught by the catch blocks you declare. It executes after the try block and exceptions caught if any. If your method throws an exception, it can't return anything unless you swallow it within your method and return result. But you can't have both.

Also, unless your method has any other code, ArrayIndexOutOfBoundsException will never be encountered either.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
2

This is because you issue a return statement before the exception is passed trough and thus a valid value is returned. You cannot both return a value and throw an exception.

Removing the finally block around the return will give the behaviour you want.

dtech
  • 13,741
  • 11
  • 48
  • 73
0

The IOException class is not a child of the ArrayIndexOutOfBoundsException class so the catch part will be never executed.

If you change to it this it will return 3.

static int retIntExc() throws Exception{
        int result = 1;
        try {
            result = 2;
            throw new ArrayIndexOutOfBoundsException ("Exception rised.");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println(e.getMessage());
            result = 3;
        } finally {
            return result;
        }
    }
Bence Olah
  • 644
  • 6
  • 10
0

I don't see why this wouldn't be expected behaviour. By the end of this code block result is equal to 2.

static int retIntExc() throws Exception{
        int result = 1;
        try {
            result = 2;

You then throw an exception, but your catch block catches exceptions of a different type so nothing is executed.

        throw new IOException("Exception rised.");
    } catch (ArrayIndexOutOfBoundsException e) {
          ...
    }

The finally block is guaranteed to be executed, so the final step is to return 2.

This successful return overrules the bubbling exception. If you want the exception to continue to bubble then you must not return in the finally block.

James Greenhalgh
  • 2,401
  • 18
  • 17
0

By putting return in finally method you override thrown exception and result is returned instead. Your code should be something like this:

static int retIntExc() throws Exception{
        int result = 1;
        try {
            result = 2;
            throw new IOException("Exception rised.");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println(e.getMessage());
            result = 3;
        } finally {
            // do something
        }
        // it gets here only when exception is not thrown
        return result;
    }
padis
  • 2,314
  • 4
  • 24
  • 30