I use final for constants. When it’s not a primitive value, I try to make sure it’s immutable.
private static final int BUFF_SIZE = 32;
private static final List<Integer> OFFSETS = Collections.emptyList();
In situations where value can’t be easily made immutable, I tend to use a lower-case name and omit the final (and preferably also static) modifier when possible.
I almost never use final on entire classes and rarely use it on methods as well. It makes certain things complicated or impossible: Mockito won’t allow you to mock a final class without an extra configuration, for example. That’s because crafting a bytecode that inherits from a final class breaks at the JVM level even with -noverify.
Consider this:
$ echo "class Foo extends Bar {}" > Foo.java
$ echo "class Bar {}" > Bar.java
$ javac Foo.java
$ echo "final class Bar {}" > Bar.java
$ javac Bar.java
$ java -noverify Foo
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.VerifyError: Final superclass Bar can't be extended
at java.lang.ClassLoader.defineClassImpl(Native Method)
...
You need to really think twice before you impose such restriction. Within your own codebase, you can change it easily any time. Ironically, it’s also within your own codebase where it’s the most useless. Since you can easily remove it, it mostly serves just a documentation purpose.
When you design a library, it’s a different story. You take away some possibilities and make yourself responsible for solving issues that may arise. That’s probably OK within a company where you have a limited amount of users and they can approach you with a question or feature request any time, but in most other cases, I believe that providing a documentation (that also explains why some method shouldn’t be overriden) and leaving the option to “be a bad boy and do it anyway” is the preferred choice. Note that this is different from visibility modifiers where you can at least use reflection.
Unlucky use of final can force someone to fork an entire project. Been there, done that. In the end, this is one of the most stupid things about Java. I’ll always find a way to work around something, even if I had to fork the project (such as in this case), and the only thing these restrictions really do is waste my time.
I wish we could have all these features (like checked exceptions, access modifiers etc), but also have a simple way around them. It would still be useful as a machine-processeable documentation, but if you were just trying something and needed to call a private method, you could do something like obj.@superSecretMethod() instead of having to resort to reflection (and, of course, add throws Exception to your temporary@Test method) or changing the modifier in a production code (and then reverting the changes back).
Brazilian Jiu Jitsu, 2020 goals / plans and figure out how to prototype an RTS game. Thinking I will just use Javascript for now.
tomaytotomato.com
Its powered by Ghost which I would recommend for simplicity of setting up and maintaining. Self hosted on a private VPS.
I use
final
for constants. When it’s not a primitive value, I try to make sure it’s immutable.In situations where value can’t be easily made immutable, I tend to use a lower-case name and omit the
final
(and preferably alsostatic
) modifier when possible.I almost never use
final
on entire classes and rarely use it on methods as well. It makes certain things complicated or impossible: Mockito won’t allow you to mock afinal
class without an extra configuration, for example. That’s because crafting a bytecode that inherits from a final class breaks at the JVM level even with-noverify
.Consider this:
You need to really think twice before you impose such restriction. Within your own codebase, you can change it easily any time. Ironically, it’s also within your own codebase where it’s the most useless. Since you can easily remove it, it mostly serves just a documentation purpose.
When you design a library, it’s a different story. You take away some possibilities and make yourself responsible for solving issues that may arise. That’s probably OK within a company where you have a limited amount of users and they can approach you with a question or feature request any time, but in most other cases, I believe that providing a documentation (that also explains why some method shouldn’t be overriden) and leaving the option to “be a bad boy and do it anyway” is the preferred choice. Note that this is different from visibility modifiers where you can at least use reflection.
Unlucky use of
final
can force someone to fork an entire project. Been there, done that. In the end, this is one of the most stupid things about Java. I’ll always find a way to work around something, even if I had to fork the project (such as in this case), and the only thing these restrictions really do is waste my time.I wish we could have all these features (like checked exceptions, access modifiers etc), but also have a simple way around them. It would still be useful as a machine-processeable documentation, but if you were just trying something and needed to call a private method, you could do something like
obj.@superSecretMethod()
instead of having to resort to reflection (and, of course, addthrows Exception
to your temporary@Test
method) or changing the modifier in a production code (and then reverting the changes back).Interesting, I will definitely think about this in future when designing classes.