46

What does final do in the following Java expression?

catch (final SomeExceptionType e)
Matteo
  • 14,696
  • 9
  • 68
  • 106
Debajit
  • 46,327
  • 33
  • 91
  • 100

4 Answers4

45

It basically means:

Catch "SomeExceptionType" into the variable "e" with the promise that we won't assign a different exception to "e" during the processing of the exception.

Mostly this is overkill, as if I'm catching an exception into a temporary variable name (e only is valid for the exception handling block), I don't have to police myself so strictly as to not trust myself to assign a different (possibly created) exception to the same variable name.

That said, perhaps this block is heavily maintained by a team of different-minded individuals, and one just wanted to be VERY sure that e was the original captured exception.

---- Edited in response to commentary ----

I can't think of a really excellent reason to do this. Since "e" is not a member (static or otherwise) the name "e" won't be used by the class file post-compilation. Another way of stating this is that when you enter the exception handling block of JVM bytecode, the object won't be assigned to any of the member names accessible by the JVM processing frame, it will be pushed to the internal processing stack of the Thread's current frame.

Even if two threads had access to the same Object, each thread would have it's own frame, so the compiler removed "e" name from one frame's internal stack couldn't be altered by the other thread.

With that in mind, the only benefit of declaring "e" final is to make sure that future coders don't accidentally set "e" after entering the block. Perhaps they meant to make the code more robust in a multi-threaded environment, but temporary variables (those with names that only are valid in the block) don't have names post-compilation, they are pushed onto the frame's stack.

That's why

public int safe() {
  int x = 5;
  x = x + 5;
  return x;
}

is generally regarded as thread safe, because it does this (in pseudo bytecode)

(In the thread's current frame)
push 5
push 5
add integers
return

While this isn't thread safe

int x = 5;

public void unsafe() {
  x = 5;
  x = x + 5;
  return x;
}

because it does this

(in the thread's current frame)
push "this"
push 5
set member x
push "this"
get member x
push 5
add integer
set member x
get member x
return

The latter bytecode makes it apparent that interleaving two threads creates thread-to-thread communications using member x an an intermediary, while the first block of code cannot have any inter-thread communication because there's no intermediary.

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
  • When would such a case happen? I'm guessing in a multithreaded environment, but could you illustrate this with a small example? – Debajit Aug 18 '10 at 21:31
  • 4
    @Nocturne: Multi-threading has nothing to do with it. Since the variable 'e' is local to the handler block, it can never be accessed from other threads. I think it might be sort-of useful if you have a long and complicated handler block - but in that case, you're probably doing it wrong anyway. – Mike Baranczak Aug 18 '10 at 21:47
  • 7
    @Nocturne: By marking "e" final, the author is forbidding "e" from being reassigned to refer to a different object in the catch block. It is a maintenance safety mechanism more than a concurrency aid, used in this manner. Attempts to reassign "e" will be caught during code compilation. – Noel Ang Aug 18 '10 at 21:51
  • 5
    I suspect the `final` might simply be the product of an automated refactoring. I can't imagine exactly which refactoring might have led to this, but it's common for refactorings to leave as much as possible final. – Carl Manaster Aug 18 '10 at 22:24
  • The final is so you can catch an exception, log it (or whatever), and then re-throw it. Prior to JDK 7, you would have to throw a new instance that wraps the original exception, creating even longer stack traces. Edit: Well, that's not technically true. You could re-throw if you caught every specific expected exception type, but you couldn't catch as Exception and re-throw that, without having to mark your method as "throws Exception". – Sophistifunk Jan 02 '13 at 01:37
  • A reason for making the exception final, could be if the original author was using a code quality check tool which considered this important. – Thorbjørn Ravn Andersen Feb 13 '13 at 12:24
  • @ThorbjørnRavnAndersen It is possible, but I haven't personally used a code quality check tool that imposed this requirement. In fact, if it did impose such a requirement, I'd say it was time to get a better code quality check tool, as this doesn't improve code quality but it costs extra time to implement. Measure the wrong stuff, and you spend time and money doing the wrong things. – Edwin Buck Feb 13 '13 at 17:22
  • People disagree on what is important. If you do not like a rule you can change it, but others may like rules you don't. The rationale for it may be interesting, though. – Thorbjørn Ravn Andersen Feb 14 '13 at 13:39
  • @ThorbjørnRavnAndersen The bytecode output for the JVM is the same with both settings. Can you justify the additional cost of changing code to fit one preference with a quality measurement that impacts something other than "it was done this way"? Improving quality is supposed to improve speed, correctness, maintainability, or something that can eventually be translated (however questionably) into saved dollars. Changes that have no impact in any of the above have no additional quality value. That's why I said the tool would be wasting your time (and money). – Edwin Buck Feb 14 '13 at 17:17
  • this answer is completely bogus, the reason you put final there is so you can use it in anonymous class inside the block – Enerccio Jul 12 '16 at 11:24
  • 1
    I was unaware that people populated their exception capturing blocks with anonymous classes. However, the question doesn't indicate that any anonymous class was within this block, so it seems that it is (without further elaboration) still unnecessary unless you really think it's going to get reassigned in such a block. – Edwin Buck Jul 13 '16 at 06:11
12

Currently it means final much the same as any local variable, other than it is always "definitely assigned".

In recent JDK7 builds, a Project Coin language change allows it to indicate a degree of implicit static typing is going on. A single catch can catch a number of different checked exceptions by a common base type, and rethrow with the enclosing context only having catch or declare those exceptions that could (statically speaking) be thrown within the try. (See the link for a better explanation.)

Community
  • 1
  • 1
Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
6

The question, "What does final do?" is addressed in other answers to this question, and here, here, and here. But in the context of a try-catch block, the Java Language Specification (JLS) §4.12.4 states (emphasis my own):

  • A resource of a try-with-resources statement (§14.20.3) and an exception parameter of a multi-catch clause (§14.20) are implicitly declared final.
  • An exception parameter of a uni-catch clause (§14.20) may be effectively final instead of being explicitly declared final. Such a parameter is never implicitly declared final.

In a multi-catch clause:

Adding the final keyword to a multi-catch clause simply makes explicit the fact that the variable is implicitly final. In general, whenever the final keyword conveys additional information that helps make your code more readable/maintainable, use it.

In a uni-catch clause

On the other hand, the exception parameter in a uni-catch clause is never implicitly final. So, using the final keyword to a uni-catch clause prevents something like the following from happening:

try {
     throw new Exception();
catch (Exception e){
    e = null;
    e.printStackTrace(); //throws a NullPointerException
}

The issue is obvious in this simple example. But two cases may be less obvious and warrant the use of final:

  1. If the catch block is more complicated, accidental reassignment is possible. (Although, if the catch block is complicated, you're probably doing it wrong.)
  2. To prevent issues caused during code maintenance. Adding final to the exception variable will ensure reassignment is caught at compilation, rather than Runtime

As a general rule of thumb, use the final keyword in a uni-catch clause in the same way you would use the final keyword for a method parameter:

JLS§4.12.4 : Declaring a variable final can serve as useful documentation that its value will not change and can help avoid programming errors.

Austin
  • 8,018
  • 2
  • 31
  • 37
  • I'm not sure that an answer for "finally" has much to do with a question about "final" – Edwin Buck Feb 22 '19 at 17:40
  • @EdwinBuck Agreed. It looks like a typo; the context of the answer doesn't have anything to do with a 'finally' block. I updated the answer to remove the ending "ly" – Austin Mar 04 '19 at 02:42
3

The final keyword on variables means that the variable can only be assigned once, and as the assignment here is being done by the compiler it means that the variable cannot be changed later in the code.

This is an important property as it means to the maintainer that this particular variable will have this particular value everywhere it is used and it is not necessary to keep track of where it changes. This is recognized to be so useful that the "Clean up" action in Eclipse allows for adding "final" whereever it possibly can, and I believe that what you see is the result of such an automatic clean up, because most human programmers would keep the catch-block short so such an indication is not needed.

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347