Question

Effective Java - Item-2 states ,

a JavaBean may be in an inconsistent state partway through its construction.

I could not understand this, If an object is being constructed in a method, how would that go inconsistent, if exception has to occur, that can occur in constructor too. And how is this related to threading?

Was it helpful?

Solution

The following bean was presented in the book:

NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);

of these, the servingSize and servings set by setServingSize(int) and setServings(int) are fundamental - at least in the book - for the nutrition facts.

But if you just call:

NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setCalories(100);

then the servings field would not be set. Thus the resulting instance is now in an invalid state.

So if you would call a method that expects a valid instance, say healthRiskCalculator.calculateHealthRisk(NutritionFacts facts) then you would get an exception either within the object or in healthRiskCalculator.

So now you could check the damage to your health when you call calculateHealthRisk() but there may be many methods that read or use the object instance. Furthermore, you may have created a lot of invalid instances for other products as well. In other words, this is not fail fast.

So there is no fail safe way of creating a constructed object using beans. This is not particular to threading, you can create an invalid bean instance within a single thread.

OTHER TIPS

Imagine a threaded model, where ThreadUtils.doFoo(FooBean fb) would spawn a thread that would work with fb. fb could be as simple as parameters to be passed to that thread to define its computation. Now, take the following constructor:

public FooBean(int i, int j, int k, int l, int port){
    ThreadUtils.doFoo(this);
    someListField = Arrays.asList(i, j, k, l);
    this.port = port;
}

This causes this to leak out of the constructor. If for some spurious reason the spawned thread acted before the list was properly instantiated and assigned, you'd have a thread working on an inconsistent state of this. If, for instance, port was used by the new thread to listen on a socket, and this got leaked, the socket may listen on port 0 (default value of a numeric field), and not on port port.

In fact, an exception in the constructor can be an issue if this is leaked and gets a reachable strong reference from elsewhere.

However, the following constructor is safe:

public FooBean(int i, int j, int k, int l, int port){
    someListField = Arrays.asList(i, j, k, l);
    this.port = port;
    ThreadUtils.doFoo(this);
}

That is because in the Java memory model, the fields are stored before the thread even gets spawned.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top