prices = ....
When the history for a stock is constructed for a given symbol s , the object creates and stores
a sorted map of prices keyed by date of all the prices between start and end . The code
also saves the firstDate and the lastDate . The constructor doesn't fill in any other fields;
they are initialized lazily. When a getter on any of those fields is called, the getter checks if
needsCalc is true . If it is, it calculates the appropriate values for the remaining fields if ne-
cessary (all at once).
This calculation includes creating the histogram , which records how many days the stock
closed at a particular price. The histogram contains the same data (in terms of BigDecimal
and Date objects) as is found in the prices map; it is just a different way of looking at the
Because all of the lazily initialized fields can be calculated from the prices array, they can
all be marked transient , and no special work is required to serialize or deserialize them.
The example is easy in this case because the code was already doing lazy initialization of the
fields; it can repeat that lazy initialization when receiving the data. Even if the code eagerly
initialized these fields, it could still mark any calculated fields transient and recalculate
their values in the readObject() method of the class.
Note too that this preserves the object relationship between the prices and histogram ob-
jects: when the histogram is recalculated, it will just insert existing objects into the new map.
This kind of optimization is almost always a good thing, but there are cases when it can actu-
ally hurt performance. Table 10-11 shows the time it takes to serialize and deserialize this
case where the histogram object is transient versus nontransient, as well as the size of the
serialized data for each case.
Table 10-11. Time to serialize and deserialize objects with transient fields
Serialization time Deserialization time Size of data
No transient fields 12.8 seconds
Transient histogram 11.5 seconds