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