In the book Java Concurrency In Practice, there is this example of an almost immutable object which is at risk of failure if not properly published:
// Taken from Java Concurrency In Practice
// p.51 Listing 3.15: Class at risk of failure if not properly published.
public class Holder {
private int n;
public Holder(int n) { this.n = n; }
public void assertSanity() {
if(n != n)
throw new AssertionError("This statement is false.");
}
}
// p.50 Listing 3.14: Publishing an object without adequate synchronization. Don't do this.
class Client {
public Holder holder;
public void initialize() {
holder = new Holder(42);
}
}
If I understand the chapter in the book correctly, adding final
to the n
field of the Holder
class will make the object completely immutable and eliminate the chance of getting the AssertionError
thrown even if it's still published without adequate synchronization like it's done in the Client
class.
Now I'm wondering how anonymous classes behave in this respect. Please see the following example:
public interface IHolder {
void assertSanity();
}
class IHolderFactory {
static IHolder create(int n) {
return new IHolder() {
@Override
public void assertSanity() {
if (n != n)
throw new AssertionError("This statement is false.");
}
};
}
}
class IHolderClient {
public IHolder holder;
public void initialize() {
// is this safe?
holder = IHolderFactory.create(42);
}
}
It's published without adequate synchronization just like in the example from the book, but the difference is that now the Holder
class has become an interface and there is a static factory method which returns an anonymous class implementing the interface, and the anonymous class uses the method parameter n
.
My question is: is there any chance of getting the AssertionError
from my latter example thrown? If there is, what is the best way to make it completely immutable and eliminate the problem? Does it change something if it was written in a functional way like the following?
class IHolderFactory {
static IHolder create(int n) {
return () -> {
if (n != n)
throw new AssertionError("This statement is false.");
};
}
}