Basic Cleaner Example

by: Ethan McCue
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.Cleaner;

public final class HasResource implements AutoCloseable {
    // This has a Thread backing it so you want to share your cleaner across the whole lib
    private static final Cleaner CLEANER = Cleaner.create();

    private final FileOutputStream outputStream;
    private final Cleaner.Cleanable cleanable;
    
    // You don't want your cleaner task to be a lambda so you don't accidentally capture a
    // ref. to the wrapping object.
    private static final class CleanerTask implements Runnable {
        private final FileOutputStream outputStream;

        private CleanerTask(FileOutputStream outputStream) {
            this.outputStream = outputStream;
        }

        @Override
        public void run() {
            try {
                this.outputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public HasResource() {
        try {
            this.outputStream = new FileOutputStream("ex.csv");
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
        this.cleanable = CLEANER.register(this, new CleanerTask(this.outputStream));
    }

    @Override
    public void close() {
        // This has "at most once" semantics so if they close it the cleaner won't run your cleanup logic a second time
        this.cleanable.clean();
    }
}

<- Index