Why private method can not be final as well?

One edge case that requires a private method to be final is when the SafeVarargs annotation is used. The following code does not compile, because the private method is not final.

@SafeVarargs
private void method(List<String>... stringLists) {
    //TODO a safe varargs operation
}

This was fixed in Java 9.
See: java @SafeVarargs why do private methods need to be final


It makes the language more flexible but the language does not guarantee that it will have any effect. Making a private method final is a hint to the (JIT) compiler.

The Java Language Specification notes that:

A method can be declared final to prevent subclasses from overriding or hiding it.

It is a compile-time error to attempt to override or hide a final method.

A private method and all methods declared immediately within a final class (§8.1.1.2) behave as if they are final, since it is impossible to override them.

At run time, a machine-code generator or optimizer can "inline" the body of a final method, replacing an invocation of the method with the code in its body. The inlining process must preserve the semantics of the method invocation. In particular, if the target of an instance method invocation is null, then a NullPointerException must be thrown even if the method is inlined. A Java compiler must ensure that the exception will be thrown at the correct point, so that the actual arguments to the method will be seen to have been evaluated in the correct order prior to the method invocation.

From Wikipedia:

A common misconception is that declaring a class or method as final improves efficiency by allowing the compiler to directly insert the method wherever it is called (see inline expansion). But because the method is loaded at runtime, compilers are unable to do this. Only the runtime environment and JIT compiler know exactly which classes have been loaded, and so only they are able to make decisions about when to inline, whether or not the method is final

Machine code compilers which generate directly executable, platform-specific machine code, are an exception. When using static linking, the compiler can safely assume that methods and variables computable at compile-time may be inlined.


Basically, it's allowed because they didn't feel like it's worthwhile to put a special case prohibiting the private modifier. It's like how you can also declare methods on an interface as public, or nested classes in an interface as static, even though those keywords are implied in interfaces. You can also declare final methods on a final class, etc.

Java took the stance of not complaining when you add redundant modifiers. They do it consistently.