同步 · dev.to / @markyu
A practical Java explanation of final, finally, and finalize using real failure modes instead of memorized definitions.
- 发布日期
- May 24 '24
- 阅读时长
- 2 min read
- 点赞
- 13
- 评论数
- 3
javabackendprogrammingbeginners
final, finally, and finalize look like siblings.
They are not.
I have seen beginners mix them up because tutorials explain them as definitions. I think they make more sense if you connect each one to the bug it prevents.
Quick Map
| Keyword / method | What it protects against |
|---|---|
final | accidental reassignment, override, or inheritance |
finally | cleanup code being skipped |
finalize | mostly historical cleanup confusion |
The uncomfortable truth: you should understand finalize, but you probably should not use it.
final: Stop Accidental Change
Use final when a value or behavior should not be changed after it is set.
public class RateLimiter {
private final int maxRequests;
public RateLimiter(int maxRequests) {
this.maxRequests = maxRequests;
}
public boolean allow(int currentRequests) {
return currentRequests < maxRequests;
}
}Here maxRequests cannot be reassigned after construction. That is boring, and boring is good.
You can also use final on methods:
class BaseService {
public final void audit() {
System.out.println("audit event written");
}
}A subclass cannot override audit(). I would use this sparingly. If you need final everywhere, your inheritance design may already be too clever.
And on classes:
public final class StringUtils {
private StringUtils() {}
}This says: do not extend this class.
finally: Cleanup Even When Things Break
finally runs whether the try block succeeds or throws.
Old-style file handling:
FileReader reader = null;
try {
reader = new FileReader("config.txt");
// read file
} catch (IOException e) {
System.out.println("read failed: " + e.getMessage());
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ignored) {
// logging would be better in production
}
}
}This works, but modern Java gives you a cleaner option:
try (FileReader reader = new FileReader("config.txt")) {
// read file
} catch (IOException e) {
System.out.println("read failed: " + e.getMessage());
}That is try-with-resources. In most production code, I would prefer it over a manual finally.
Still, finally matters when cleanup is not an AutoCloseable resource:
lock.lock();
try {
updateSharedState();
} finally {
lock.unlock();
}This is the real bug finally prevents: a lock stays locked because an exception jumped over your cleanup line.
finalize: Know It, Then Avoid It
finalize() was intended to run before garbage collection reclaims an object.
@Override
protected void finalize() throws Throwable {
System.out.println("cleanup before GC");
}Do not build production cleanup around this.
Why?
- You do not control when GC runs.
- It may run much later than expected.
- It adds performance and reliability problems.
- It has been deprecated for removal in modern Java.
If you need cleanup, use AutoCloseable:
class ConnectionHandle implements AutoCloseable {
@Override
public void close() {
System.out.println("connection closed");
}
}
try (ConnectionHandle handle = new ConnectionHandle()) {
System.out.println("using connection");
}This is explicit. You can reason about it. Production code likes that.
The Rule I Use
- Use
finalto make intent harder to accidentally break. - Use
finallywhen cleanup must happen even after exceptions. - Avoid
finalize; use explicit cleanup instead.
Final Thought
These three names are confusing, but the responsibilities are not.
final is about preventing change. finally is about guaranteed cleanup. finalize is a legacy GC hook you should not lean on.
Which Java keyword confused you the most when you first learned backend development?
相关阅读
Java throw vs throws: The Exception Bug They Reveal
A practical Java exception handling guide explaining throw, throws, checked exceptions, runtime exceptions, and API boundary decisions.
java
Java BeanUtils Copying: Convenient, but Not Free
A practical Java guide to BeanUtils, shallow copy pitfalls, reflection overhead, and when MapStruct or manual mapping is a better choice.
java
Frontend Linear Data Structures Deep Dive: Arrays, Stacks, Queues, and Linked Lists
The Big Picture Before diving into stacks, queues, and linked lists, it helps to know...
computerscience
原文发布
本文首发于 dev.to,评论与点赞保留在原站。
在 dev.to 继续阅读