M4RKYU.SYSEdition 2027
Skip to content
LOCEN/Ontario · CA/▸logs · understanding final finally and finalize in java 3p0hStandbyOK/--:--:--EST
M4M4RK_YUportfolio
  • BuildBuild
    BuildOverview
    • WorkSelected case studies and write-ups
    • GamesPlayable prototypes and game-dev logs
  • GalleryGallery
    GalleryOverview
    • PhotosPhoto collections and visual experiments
    • ShopPrints, posters, and one-off objects
  • WritingWriting
    WritingOverview
    • BlogLong-form devlogs and field notes
    • NotesShort observations, links, snippets
  • ResourcesResources
    ResourcesOverview
    • Tools38 in-browser developer utilities
    • LinksDaily-use dev and design bookmarks
  • AboutAbout
  • ContactContact
中文

syndicated · dev.to / @markyu

Java final, finally, finalize: Three Bugs They Prevent

A practical Java explanation of final, finally, and finalize using real failure modes instead of memorized definitions.

Published
May 24 '24
·
Reading time
2 min read
·
Reactions
13
·
Comments
3
javabackendprogrammingbeginners
View on dev.toDiscuss

On this page

  • Quick Map
  • final: Stop Accidental Change
  • finally: Cleanup Even When Things Break
  • finalize: Know It, Then Avoid It
  • The Rule I Use
  • Final Thought

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 / methodWhat it protects against
finalaccidental reassignment, override, or inheritance
finallycleanup code being skipped
finalizemostly 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 final to make intent harder to accidentally break.
  • Use finally when 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?

Related reading

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

originally published

This post first ran on dev.to. Comments and reactions live there.

Continue on dev.to
PreviousJava throw vs throws: The Exception Bug They RevealA practical Java exception handling guide explaining throw, throws, checked exceptions, runtime exceptions, and API boundary decisions.
Back to all posts
NextDatabase Table Design Starts With the Queries You NeedA practical database table design guide focused on queries, keys, indexes, normalization, constraints, and production tradeoffs.
Back to archive
M4RKYUM4RKYUM4RKYUM4RKYUM4RKYUM4RKYUM4RKYUM4RKYU
Crafted since 2024
ZhenXiao Mark YuZhenXiao Mark Yu
get in touch

Saw something here?Tell me about it.

It's a portfolio, not a service · but I read every note — drop a line if anything here resonated, or just to say hi.

Start a conversation
open channel

say hi anytime · 2026

--:--:--ESTOntario, Canada
  • Email
  • GitHub
  • dev.to
  • LinkedIn
  • Twitter / X
  • Instagram
  • Facebook
  • YouTube
  • CodePen
  • Spotify
  • Snapchat

Newsletter

Get the occasional dispatch

Notes and logs from m4rkyu.com — short, dated, no noise. Unsubscribe anytime.

Work

Production builds, games, and visual archives.

  • Projects
  • Games
  • Archive
  • Logs

Resources

Daily-use tools and a personal link library.

  • Search
  • Latest
  • Tools
  • Links
  • Notes
  • Topics
  • Shop
RSSJSON feed

Studio

Background, contact, and channels for collaboration.

  • About
  • Contact
  • Changelog
  • Colophon
  • Resumepending

Socials

Find me on the usual feeds.

  • GitHub
  • dev.to
  • LinkedIn
  • Twitter / X
  • Instagram
  • Facebook
  • YouTube
  • CodePen
  • Spotify
  • Snapchat
  • Email
© 2026 ZhenXiao Mark Yumarkyu0615@gmail.com
  • Email
  • GitHub
  • dev.to
  • LinkedIn
  • Twitter / X
  • Instagram
  • Facebook
  • YouTube
  • CodePen
  • Spotify
  • Snapchat
PrivacyTermsBuilt with Next.js 16 · React 19 · Tailwind 4