The compiler is smart enought o know all of the possible ways for the method to exit and can check them for proper return values. Inthe example given the code will
always throw an Exception so the catch will always be exectued and the method will always return a value as required. To see the compiler check the code look at this:
When compiled the way it is above the compiler will produce an error saying the method does not return a value because with line 1 commented out and line 2 uncommented it will throw an uncaught NumberFormatException, so the exception is thrown then finally executes and at no point does it get to a return statement.
If you uncomment line 1 and comment line 2 it will still give you an error because you have a catch block that does not have a return statement.
So the compiler can figure out all of the exits from your method and
test the for correctness - that's why you dont get an error in the original code.
This example uses RuntimeExceptions but the principle will be the same for checked Exceptions too.
hope that helps clear it up for you