Is there ever a reason to not use the final keywor

2019-01-23 23:49发布

问题:

I've seen some code as below in some example BlackBerry Java classes:

try
{
    // stuff that will throw an exception
}
catch(final Exception e)
{
    // deal with it
}

I presume the final is for performance. As per the title, since there's rarely (ever?) any reason to modify an Exception that's already been thrown, should they always be final?

If so, isn't this something that could be done by the compiler? Or is it done by the compiler and adding the final manually has no impact at all?

回答1:

The Java Language Specification 11.2.2 makes a difference between final and not final exceptions:

A throw statement (§14.18) whose thrown expression has static type E and is not a final or effectively final exception parameter can throw E or any exception class that the thrown expression can throw.
[...]
A throw statement whose thrown expression is a final or effectively final exception parameter of a catch clause C can throw an exception class E iff:

  • E is an exception class that the try block of the try statement which declares C can throw; and
  • E is assignment compatible with any of C's catchable exception classes; and
  • E is not assignment compatible with any of the catchable exception classes of the catch clauses declared to the left of C in the same try statement.

Interestingly, JLS 14.20 also says:

In a uni-catch clause, an exception parameter that is not declared final (implicitly or explicitly) is considered effectively final if it never occurs within its scope as the left-hand operand of an assignment operator.

In other words, if you don't reassign the e of your catch statement (like e = new SomeOtherException();), it is implicitly declared final.

So I can only conclude that it does not make a difference, unless the exception is modified in the catch block and the only example I can come up with is:

public void method1() throws IOException {
    try {
        throw new IOException();
    } catch (Exception e) { // e is not modified in catch => implicitly final
        throw e; //compiles OK
    }
}

//it works because method1 is semantically equivalent to method2:
public void method2() throws IOException {
    try {
        throw new IOException();
    } catch (final Exception e) {
        throw e;
    }
}

public void method3() throws IOException {
    try {
        throw new IOException("1");
    } catch (Exception e) {
        e = new IOException("2"); //e modified: not implicitly final any more
        throw e; //does not compile
    }
}


回答2:

I believe final is useful when the code which could use it is too long to easily read and understand. e.g. I would make fields final where possible to ensure they are assigned correctly in constructors and not modified anywhere in the class.

Using final for a catch clause is unlikely to help much as a) the value is guaranteed to be set b) the code using it should be short, c) its very rare to modify it anyway.

There is nothing stopping you from doing it however.



回答3:

I'm not sure it's about performance, but more about convention. If you're using Eclipse, try to set a formatter that add the final keyword wherever it's possible, and reformat your source code with that formatter.



回答4:

I've seen a couple of projects where everything what is not modified must be final (e.g. parameters, fields, local vars etc).

There's also a correspondent style check in PMD code analyzer, which verifies that everything what possible is declared as final.



回答5:

I doubt final would really give any performance benefit because the exception instance is block local (Here is a really good answer explaining it https://stackoverflow.com/a/306966/492561).

So It merely serves as a explicit marker that says I will not modify.

Some times you may need to modify the exception to throw it back, may be edit the message to make it more clear at higher levels.

Essentially I would say that its a matter of preference, Some may like it others may not.