Hi Peter,

Tricky indeed,  the visibility of what is captured is too subtle.
Even if the field is final, it captures this, not the value.
I suppose it is more efficient not to copy field values.

But other than recommending capturing only local variables and arguments,
is there any other relevant advice?

I added examples of both nested class based and lambda based cleaners to the
Cleaner javadoc in the @apiNote.


[1]http://cr.openjdk.java.net/~rriggs/webrev-cleaner-8138696/
[2]http://cr.openjdk.java.net/~rriggs/cleaner-doc/index.html

Thanks, Roger


On 12/08/2015 01:51 PM, Peter Levart wrote:


On 12/08/2015 04:34 PM, Roger Riggs wrote:
Hi Peter,

Thanks for the example and explanations.

For simple cleanup of specific state values, I probably would have used lambda instead of an explicit
inner class but both styles use the same mechanism.
The point about using a shared cleaner can be reinforced in the example too.

public static class CleanerExample implements AutoCloseable {

        FileDescriptor fd = ...;

        private static final Cleaner cleaner = Cleaner.create();

private final Cleaner.Cleanable cleanable = cleaner.register(this, () -> fd.close());

        @Override
        public void close() {
            cleanable.clean();
        }
    }


Sorry Roger, but this example is flawed. This is tricky! The lambda "() -> fd.close()" captures 'this', not only 'fd' as can be seen by running the following example:

public class Test {

    int x = 0;

    final IntSupplier xSupplier = () -> x;

    public static void main(String[] args) {
        Test t = new Test();
        System.out.println(t.xSupplier.getAsInt());
        t.x = 12;
        System.out.println(t.xSupplier.getAsInt());
    }
}

...which prints:

0
12


To correct that, but still use lambda, you would have to capture a local variable, like:

public class Test {

    int x = 0;

    final IntSupplier xSupplier;

    {
        int xValue = x;
        xSupplier = () -> xValue;
    }

    public static void main(String[] args) {
        Test t = new Test();
        System.out.println(t.xSupplier.getAsInt());
        t.x = 12;
        System.out.println(t.xSupplier.getAsInt());
    }
}


...now prints:

0
0


Regards, Peter



Reply via email to