What is the difference between Final, Finally and Finalize in Java? This is a common question in Java interviews. How are they different?

These three look very similar, in fact their relationship is like Kaspersky and Pakistan has kibar relationship.

So how do you answer this question? First of all, we can briefly introduce the differences of the three from the perspective of syntax and usage:

  • Final can be used to modify classes, methods, and variables, respectively, with different meanings. The class modified by final means cannot inherit extensions, final variables cannot be modified, and final methods cannot be overridden (override).
  • Finally is Java’s mechanism for ensuring that important code must be executed. You can use try-finally or try-catch-finally to close a JDBC connection and ensure that an UNLOCK is unlocked.
  • Finalize is a method of the base java.lang.Object class that is designed to ensure that an Object completes the collection of a specific resource before being garbage collected. The Finalize mechanism is now deprecated and was marked deprecated as of JDK 9.

If you stop there, there’s no point, and we can go a little deeper into the differences, such as performance, concurrency, object life cycle, or the basic garbage collection process.

final

The final keyword is used to clarify the semantic, logical intent of the code, such as:

Declaring a method or class final makes it clear to others that these behaviors are not allowed to change. The definition or source code of the Java core class library, such as many classes under the java.lang package, is declared as final classes, such as our common String class, in some of the base classes of the third party class library, which effectively prevents API users from changing the base functionality. To some extent, this is necessary to ensure platform security.

Using final to modify parameters or variables is also a clear way to avoid programming errors caused by unexpected assignments, and it is even explicitly recommended that all method parameters, local variables, and member variables be declared final.

Final variables are somewhat immutable and can be used to protect read-only data, especially in concurrent programming, because explicitly no final variables can be assigned, reducing additional synchronization overhead and eliminating the need for defensive copying.

There have been many articles and books about the potential performance benefits of final in specific scenarios, such as the possibility that using final can help JVMS inline methods, improve the ability of compilers to perform conditional compilation, and so on. I introduced it in the previous article. If you want to know more, you can click on it.

Extended Reading: In-depth understanding of the final keyword in Java

The final and immutable

Final is not the same as immutable, as shown in this code:

final List<String> strList = new ArrayList<>();
strList.add("wupx");
strList.add("huxy");  
List<String> loveList = List.of("wupx", "huxy");
loveList.add("love");Copy the code

Final only prevents strList references from being assigned, but the behavior of strList objects is not affected by final. Adding elements and so on is perfectly normal. If we really want objects themselves to be immutable, then we need corresponding classes that support immutable behavior. In the example above, the list. of method creates itself as an immutable List, and the final add will throw an exception at runtime.

Immutable is an excellent option in many situations, in the sense that the Java language does not currently have native Immutable support. To implement Immutable classes, we need to:

Declare the class itself final so that no one else can extend it to get around the restriction.

Define all member variables as private and final, and do not implement setter methods.

When constructing objects, member variables are initialized using deep copies rather than directly assigned, which is a defensive measure because you can’t be sure that the input object won’t be modified by someone else.

If you really need to implement getter methods, or other methods that might return internal state, use the copy-on-write principle to create a private copy.

With regard to setter/getter methods, many people prefer to generate them all at once using an IDE or Lombok, and it is best to implement them when necessary.

finally

For finally, knowing how to use it is enough. The try-with-Resources statement added in Java 7 is more recommended for resources such as connections that need to be closed, because the Java platform is generally better able to handle exceptions and reduce the amount of code.

In addition, there are some commonly asked finally problems. For example, what does the following code output?

try { // do something System.exit(1); } system.out. println("Hello, I am finally." ); }Copy the code

The code in finally above will not be executed because the try-catch exception exits.

There are other cases where code in finally will not execute:

// Try {while(ture){system.out.println ("always run"); } }finally{ System.out.println("ummm"); } // Thread killed When the thread executing try-finally is killed, the code in finally cannot execute.Copy the code

finalize

Object.Finalize () is not recommended for Finalize, and in Java 9, Object.Finalize () is marked as deprecated.

Why is that? It is impossible to guarantee when Finalize will be implemented and whether the implementation is in line with expectations. Improper use can affect performance, resulting in program deadlocks, hangs, and so on.

In general, using the try-with-resources or try-finally mechanism mentioned above is a good way to recycle resources. If you do need additional processing, consider a Cleaner mechanism provided by Java or other alternatives.

Why not finalize?

Finalize is not recommended. Why not use it?

  1. The execution of Finalize is associated with garbage collection. Once a non-empty Finalize method is implemented, the corresponding object collection rendering will be order of magnitude slower.
  2. Finalize is designed to be called before an object is garbage collected, and the JVM does extra processing to it. Finalize is essentially an obstacle to fast collection, which may result in objects being collected after multiple garbage collection cycles.
  3. Finalize slows down garbage collection and leads to a large number of objects accumulation, which is also a typical cause of OOM.
  4. Be sure to recycle resources because they are limited and the unpredictable timing of garbage collection can greatly increase resource usage.
  5. Finalize will cover up the error message during resource collection.

Therefore, we should not expect Finalize to take the primary responsibility of resource release for consuming very high frequency resources. It is recommended that resources be explicitly released when they are used up or reused using resource pools.

Java.lang.ref. Finalizer () : java.lang.ref.Finalizer () : Java.lang.

private void runFinalizer(JavaLangAccess jla) { // ... Try {Object finalizee = this.get(); if (finalizee ! = null && ! (finalizee instanceof java.lang.Enum)) { jla.invokeFinalize(finalizee); // Clear stack slot containing this variable, to decrease // the chances of false retention with a conservative GC finalizee = null; } } catch (Throwable x) { } super.clear(); }Copy the code

For those of you who have read the exception article, you can quickly see that Throwable is swallowed, which means that when an exception or error occurs, no valid information is available.

Read more: 20 Best Practices for Java exception Handling. How many do you know?

Is there a better way to replace Finalize?

The Java platform is gradually replacing the original Finalize implementation with java.lang.ref.Cleaner. The Cleaner implementation makes use of PhantomReference, a common so-called post-mortem cleaning mechanism. By using phantom references and reference queues, we can ensure that objects can do some work like resource reclamation before being completely destroyed, such as closing file descriptors (limited resources of the operating system), which is lighter and more reliable than Finalize.

Each Cleaner operation is independent, has its own running thread, so can avoid accidental deadlocks and other problems.

We can build a Cleaner for our module, and then implement the corresponding cleaning logic, the specific code is as follows:

/** * Cleaner is a class for closing resources, which functions like finalize method * Cleaner has its own thread, after all cleaning operations are completed, Exceptions thrown by GC are ignored and the cleanup method (a Runnable) is run only once. Runs in two cases: * 1. The registered Object is in phantom reference state * 2. Explicitly calling clean * * Implemented through phantom references and reference queues * Multiple objects can be registered, usually defined as static (reducing the number of threads) * Cleanable objects returned after registering objects are used for explicitly calling clean * objects that implement the clean behavior (state below), The second CleaningExample will not be cleaned if the State class below is changed to non-static, * because the non-static inner class holds references to external objects, */ public class CleaningExample implements AutoCloseable {public static void main(String[] args) {try { Try (CleaningExample ignored = new CleaningExample()) {throw new RuntimeException(); }} Catch (RuntimeException ignored) {} Call the clean method by GC new CleaningExample(); System.gc(); } private static final Cleaner CLEANER = Cleaner.create(); // If it is a non-static inner class, Static class State implements Runnable {State() {} @override public void run() {system.out.println ("Cleaning called"); } } private final State state; private final Cleaner.Cleanable cleanable; public CleaningExample() { this.state = new State(); this.cleanable = CLEANER.register(this, state); } @Override public void close() { cleanable.clean(); }}Copy the code

State is defined as static in order to avoid a common inner class implying a strong reference to an external object, which would prevent the external object from entering an illusory reachable State.

From the perspective of predictability, the improvement degree of Cleaner or phantom references is still limited, and problems will also occur if phantom references are piled up due to various reasons. Therefore, Cleaner is suitable as a final guarantee means, rather than completely rely on Cleaner for resource recovery.

conclusion

This article first analyzes final, finally, Finalize from the perspective of grammar, and then goes further from the aspects of security, performance, garbage collection, etc., explaining the differences among final, Finally, Finalize in detail.

This article is published by OpenWrite!