If an exception is caught (which is the case here) the program does not end abruptly. What happens here? An ArithmeticException is thrown because of a division by 0. The first catch block will execute, hence 1 is printed. When the catch block has finished, the control goes to the finally block and 4 gets printed. When the finally is over, the try-catch-finally is over too and the execution flow goes on, that is, continues after the try-catch-finally block and prints 5. Note that only one catch block is executed, and the finally block is always executed. If the exception that has been thrown is caught by a catch block then the execution continues normally after the catch (and finally if present). If no catch block can catch the exception then the finally block (if present) is executed and the method returns abruptly by throwing the exception in the caller method.
This is about understanding how the try/catch/finally blocks work. The code in the try block first executes. This statement is designed to produce an ArithmeticException: int i = 5/k because k has been previously set to 0. Once an exception is thrown, execution of the try block immediately stops, and control passes to the first catch block that can handle the exception. Since the exception being throw is an ArithmeticException, and the very first exception handler catches an Arithmetic exception, the code in this block executes. This results in the number "1" being printed to the console. As there are no more statements in the catch block, control then passes to the finally block. Note, at this point, since the exception was caught by a handler, it is considered "Handled". That means, after the catch block completes, the exception has been completely dealt with and will not be propigated any further. If a try block ends with a finally, regardless of whether there is a catch or not, the finally block ALWAYS exectues. So in this case, the statement in the finally executes, and the number "4" is printed to the console. Next, remember I told you that the exception was considered "handled". So now control passes from the finally block to the next statement outside of the whole try/catch/finally block. This causes the number "5" to be printed.
Now, if you remove the ArithemeticException handler, then this changes the program flow like this: the zero division throws an ArithemeticException. Execution of the try block halts, and the first handler that can handle the exception runs. In this case, since RuntimeException is the superclass of ArithmeticException, an ArithmeticException IS a RuntimeException. So the RuntimeException handler gets executed. This causes the number "2" to be printed. The next statement is a return. This would ordinarily immediately transfer control of the method to the caller of the method, ie, the method would exit. However, remember I said that the finally block if present ALWAYS runs. So before this method can exit, the statements in the finally must execute, and this is what causes the number "4" to be printed. After the statements in finally have completed, control passes back to the return statement in the catch block, and control passes to the caller of the current method; since the JVM called main originally, main now exists and the JVM exits as well.