value added

5
7 4 Java Report | APRIL 2000 h t t p : / / w w w. j av a re po rt . co m T HE TERM VALUE can refer to the desirabil- ity of a thing or to an amount. While I’m not sure that Java’s type system is up to model- ing desirability, we can readily see that calculating and storing amounts is a typical require- ment of software. Value objects 1 represent the simple, granular pieces of information you find in a system: strings, dates, money, dimensions, colors, etc. This is in contrast to entity objects—which capture the significant, persis- tent pieces of information real estate such as orders and customers—and to process and service objects such as Command objects, 2 servlets, and layout managers. Patterns A pattern language relates a set of practices. Patterns are arranged so they flow from one to another, with decisions taken to go from one to the next, forming a design around a particular m o d e l — i n t h i s case, value-based programming in Java. Figure 1 shows the patterns and their connections in the language. Although the flow in the language is not linear, this column is. The following sections list the patterns in a kind of best-fit, partial ordering. Each pattern is pre- sented in a brief problem/solution form, preceded by a sentence summarizing the intent. A simple date rep- resentation example runs throughout, but you can find these patterns applied in many Java systems, includ- ing the JDK. Common Forces and Consequences Common constraining forces and common resulting consequences are a feature of many of the patterns; other patterns work to offset these. Values tend to make up a lot of the representa- tion of and method traffic between other objects. As objects, this may lead to an increase in the number of classes at development time and the creation of more small objects at runtime. However, these con- sequences and their relative impact depend on the system being built. They must be weighed against an overall reduction in duplicated logic—and there- fore system size and effect of change—and an in- crease in code clarity. As part of other objects, values often require per- sistence; as part of remote method communication, they should be copied rather than stand as targets for independent communication. Implementing Serializ- able is a solution to both of these issues. Threading is another common issue confronting the developer: To satisfy the principle of least aston- ishment, the class provider should ensure either that the effects of any modifier methods on classes are thread safe, or that class users are made aware of the lack of thread safety. Whole Value Provide distinct classes to express distinct domain specific value quantities clearly and safely. Problem. How can you represent a primitive domain quantity in your system without loss of meaning? It is tempting, and indeed common, to represent value quantities in a program in the most fundamental units possible, e.g., integers and floating point numbers. However, this fails to communicate the understand- ing of the problem and its quantities into the solution, Kevlin Henney is an independent consultant and trainer based in the UK. He can be contacted at [email protected]. Kevlin Henney / [email protected] Patterns in Java Value added Figure 1. Patterns and their successors for supporting value- based programming in Java. WHOLE VALUE IMMUTABLE VALUE MUTABLE COMPANION VALUE CLASS CLASS FACTORY METHOD COPIED VALUE ENUMARATION VALUES

Upload: kevlin-henney

Post on 17-Jul-2015

190 views

Category:

Software


1 download

TRANSCRIPT

Page 1: Value Added

7 4 Java™Report | A P R I L 2 0 0 0 ht t p : / / w w w. j ava re po rt . co m

THE TERM VALUE can refer to the desirabil-ity of a thing or to an amount. While I’m nots u re that Java’s type system is up to model-ing desirability, we can readily see that

calculating and storing amounts is a typical re q u i re-ment of software .

Value objects1 re p resent the simple, granular piecesof information you find in a system: strings, dates,m o n e y, dimensions, colors, etc. This is in contrast toentity objects—which capture the significant, persis-tent pieces of information real estate such as orders andcustomers—and to process and service objects such as

C o m m a nd o b j e c t s ,2 s e rv l e t s ,and layout managers.

Pat te rn sA pattern language re l a t e sa set of practices. Pattern sare arranged so they flowfrom one to another, withd e c i s i o n s t a k e n t o go fro mo n e t o t h e next, forming adesign around a part i c u l a rm o d e l — i n t h i s case, value-based pro g r a m m i n gin Java. Figure 1 shows the

p a t t e rns and their connections in the language.Although the flow in the language is not linear, this

column is. The following sections list the patterns ina kind of best-fit, partial ordering. Each pattern is pre-sented in a brief problem/solution form, preceded bya sentence summarizing the intent. A simple date re p-resentation example runs throughout, but you can fin dthese patterns applied in many Java systems, includ-ing the JDK.

Common Fo rces and Co n s e q u e n ce sCommon constraining forces and common re s u l t i n gconsequences are a feature of many of the pattern s ;other patterns work to offset these.

Values tend to make up a lot of the re p re s e n t a-

tion of and method traffic between other objects. Asobjects, this may lead to an increase in the numberof classes at development time and the creation ofm o re small objects at runtime. However, these con-sequences and their relative impact depend on thesystem being built. They must be weighed againstan overall reduction in duplicated logic—and there-f o re system size and effect of change—and an in-c rease in code clarity.

As part of other objects, values often re q u i re per-sistence; as part of remote method communication,they should be copied rather than stand as targets forindependent communication. Implementing S e r i a l i z-a b le is a solution to both of these issues.

T h reading is another common issue confro n t i n gthe developer: To satisfy the principle of least aston-ishment, the class provider should ensure either thatthe effects of any modifier methods on classes aret h read safe, or that class users are made aware of thelack of thread safety.

Whole Va l u eP rovide distinct classes to express distinct domains p e c i fic value quantities clearly and safely.

Pro b l e m . How can you re p resent a primitive domainquantity in your system without loss of meaning? It istempting, and indeed common, to re p resent valuequantities in a program in the most fundamental unitspossible, e.g., integers and floating point numbers.H o w e v e r, this fails to communicate the understand-ing of the problem and its quantities into the solution,

Kevlin He n n ey is an indepe n d e nt co n s u l t a nt and trainer basedin the UK.He can be co nt a cted at kev l i n @ a c m . o rg.

Kevlin He n n ey / [email protected] in Java

Value added

Figure 1. Pa t te rns and their successors for suppo rting va l u e -

based prog ramming in Java .

WHOLEVALUE

IMMUTABLEVALUE

MUTABLECOMPANION

VALUECLASS

CLASS FACTORYMETHOD

COPIEDVALUE

ENUMARATIONVALUES

Page 2: Value Added

7 6 Java™Report | A P R I L 2 0 0 0 ht t p : / / w w w. j ava re po rt . co m

Patterns in Java / Kevlin He n n ey

and shows poor use of the checked type system.Consider initializing a date object from the year, month,

and day. The following code fragment arbitrates a more in-t e rnational (and logical) solution to the DD/MM/YYYY ver-sus MM/DD/YYYY convention:

public final class Date ...{

public Date(int ye a r, int mo nth, int day) .... . .

}

H o w e v e r, an i nt is a pretty meaningless unit of currency: Itdoes not define its units and it cannot be checked for sen-sible use. Compile-time errors should always be pre f e rre dto runtime errors—it can mean the diff e rence between de-bugging before a release or after it:

Date right = new Date(ye a r, mo nth, day);Date wro ng = new Date(day, mo nth, ye a r ) ;Date als o Wro ng = new Date(mo nth, day, ye a r ) ;

Solution. Express the type of the quantity as a class.A Whole Value3 recovers the loss of meaning and check-ing. A Whole Value class can range from a simple wrap-per class—making the intent of the code clearer toboth the human reader and the compiler—to one withm o re complete behavior. A W ho le Va l u e makes amethod interface clearer and safer; whether it is usedin the encapsulated implementation—as opposed tore v e rting to raw values—depends on other designchoices and preferences.

Listing 1 demonstrates how a simple Ye a r class elevatesyears to a checkable and named quantity.

Ye a r could be made a little more sophisticated, acquiringthe fuller trappings of a Value Class and some range check-ing. To make D a t e initialization safe, either one or both ofmonths and days should also be re p resented by a W ho le Va l u e. Now, only the correct combination will compile:

new Date(Ye a r. va l u e O f ( year), Mo nt h . va l u e O f ( mo nth), day)

W ho le Va l u e allows us to enforce rules of combination thata re not possible with simpler types such as i nt, do u b le, orS t r i ng. This can be likened to dimensional analysis in thephysical sciences: It is plain nonsense to divide a mea-s u rement of distance by a measurement of temperature andassign the result as a measure of acceleration. A W ho le

Va l u e can wrap up a more primitive type, e.g., P ho ne N u m b e rwrapping S t r i ng; or bundle together simple attributes, e.g.,D i me ns i o n wrapping i nts for width and height.

Value Cl a s sD e fine features for a class that re p resents a value type sothat it conforms to expectations.

Pro b l e m . Having established that a value type needs implementing as a class, often because it is a W ho le Va l u e re p resenting a domain specific quantity, what stepsmust be taken to define the class so that it meets user e x p e c t a t i o n s ?

The use of value objects revolves around their re p re-sented content rather than their state: Comparisons and o rdering between value objects should depend on their content and not on their re f e rence identity. This applies totheir use as keys in associative collections as well as them o re obvious comparisons for equality.

So l u t i o n . O v e rride the methods in O b je c t whose actionshould be related to content and not identity (e.g., e q u a ls)and, if appropriate, implement S e r i a l i z a b le.

Field by field comparison is more appropriate for values than the default, identity-based O b je c t . e q u a ls. Listing2 shows e q u a ls d e fined with minimum casting and clutter.

If you override e q u a ls you should also override h a s h C o de,ensuring that if two objects compare equal so do their hash values. Related to equality comparison is general relational comparison. Not all values can be meaningful-ly compared, e.g. C o lo r, but where it makes sense, e.g., D a t e,provide a compareTo method. If you are using JDK 1.2 youcan publicize this feature more explicitly by implement-ing the Comparable interface.

Value objects are normally the kind of object that shouldp rovide a printed form. Overriding O b je c t . to S t r i ng a l l o w sclass users to take advantage of simple string concatenations y n t a x :

S ys t e m . o u t . p r i nt l n ( “ T he date today is “ + Date. to d a y ( ) ) ;

L I S T I N G 2 .

The implementation of e q u a ls for the Date Va l u e c l a s s.public final class Date ...{

. . .public boolean equals ( O b ject rhs ){

return rhs ins t a nc e of Date && equals((Date) rhs ) ;}public boolean equals(Date rhs ){

return rhs != null && rhs. year == year &&r hs. mo nt h . e q u a ls ( mo nth) && rhs.day == day;

}p r i vate int ye a r, day;p r i vate Mo nth mo nt h ;

}

L I S T I N G 1.

Ye a r re p resented as a simple W ho le Va l u e.public final class Ye a r{

public static Year va l u e O f ( i nt ye a r ){ return new Ye a r ( year); }

public Ye a r ( i nt year) { value = year; }public int ge t Value() { return value; }p r i vate final int va l u e ;

}

Page 3: Value Added

7 8 Java™Report | A P R I L 2 0 0 0 ht t p : / / w w w. j ava re po rt . co m

C reating instances of a Value Class can be simplified by p roviding Class Fac to r y Me t ho d s as well as, or instead of, pub-lic constru c t o r s .

En u m e ration Va l u e sR e p resent a distinct and bounded set of values as objects.

Pro b l e m . How can you re p resent a fixed set of constant val-ues and pre s e rve type safety? It is commonly the case thata fixed set of options or indicators need re p re s e n t a t i o n .Even if they have no specific values they must still be dis-tinct from one another.

For example, assuming you count months from January,do you number from 0 or from 1? A good case can be madefor either one, which is exactly the problem with raw,meaningless i nts. That said, there is a question of consis-tency over any API that thinks it is reasonable to startmonths from 0 and days from 1. Given that Java defaults i ntfields to 0—potentially hiding initialization pro b l e m s — i tseems best to opt for the 1 convention.

Now that the decision has been made, how can it bee n f o rced? The simplest way to communicate this intentwith the user is to use named i nt constants. Although thisis preferable to inviting users to plug in magic numbers,it is still open to intentional or accidental abuse: i nt i schecked only as an i nt and not as a month. Modelingmonth as a W ho le Va l u e o ffers a more expressive appro a c h ,but does not necessarily constrain the set of values to thec o rrect ones.

So l u t i o n . Treat each constant as a W ho le Va l u e i n s t a n c e ,declaring it as public static fin a l in the W ho le Va l u e class. Toe sure that the set of constant values remains fixed, p revent public construction by defining the constructor asprivate. Implementing the class as an I m mu t a b le Va l u ep revents the possibility of the constant values being unexpectedly nonconstant.

Users of the Mo nt h class can now both name themonth of their choice and receive the full support of thec o m p i l e r’s type checking. Also, because the type implicitly restricts the E nu me ration Va l u e s, range check-ing is fre e .

W h e re the primitive value associated with each of the

E nu me ration Va l u e s has special significance—which is thecase for months—the initialization of each constantshould be explicit and fully under the control of theclass developer (see Listing 3). Otherwise a no-arg c o n s t ructor and a static counter can be used to assigneach constant value a distinct number based on order of initialization.

Class Fa cto ry Me t h odP rovide a convenient way to create an object that encap-sulates the details of cre a t i o n .

Pro b l e m . How can you simplify, and potentially optimize,c o n s t ruction of Value Class objects in expressions withoutre s o rting to intrusive new expressions? How do you pro-vide for the opportunity to reuse existing objects that havethe same value, i.e., F l y we i g ht o b j e c t s ?2

Assuming that year and month are re p resented by W ho leVa l u e objects, the following code to initialize a D a t e l o o k ssyntactically clumsy and does not support the use of E nu-me ration Va l u e s for months:

Date clumsy = new Date(new Ye a r ( year), new Mo nt h ( mo nth), day);

So l u t i o n . P rovide s t a t i c methods to be used instead of (oras well as) ord i n a ry constructors. The methods re t u rn ei-ther newly created Value Class objects or existing objects fro ma lookup table (see Listing 4).

For value types with a clear and commonly used stringre p resentation, it is common to provide a Class Fac to r yMe t ho d that takes a S t r i ng and re t u rns a value object basedon the parsing of that string. For example, Mo nt h may pro-vide a conversion from the month name to the relevant E nu-me ration Va l u e.

Even when it does not offer a lookup optimization, aClass Fac tory Me t ho d has benefits in promoting uniform us-age and syntactic simplification. Class Fac tory Me t ho d is acommon variation of the vanilla Fac tory Me t ho d p a t t e rn .2

Copied Va l u e*

Describe how modifiable value objects should be passeda round so as to avoid aliasing pro b l e m s .

Pro b l e m . How can you pass a modifiable Value Class

Patterns in Java / Kevlin He n n ey

L I S T I N G 3 .

Mo nt hs ex p ressed as E nu me ra t ion Va l u e s.public final class Mo nth ...{

public static final Mo nth january = new Mo nt h ( 1 ) ;. . .public static final Mo nth december = new Mo nt h ( 1 2 ) ;public int ge t Value() { return value; }. . .p r i vate Mo nt h ( i nt mo nth) { value = mo nth; }p r i vate final int va l u e ;

}

L I S T I N G 4 .

A Class Factory Me t ho d that converts from i nt to Mo nt h.public final class Mo nth ...{

. . .public static Mo nth va l u e O f ( i nt mo nt h )

{ return mo nt hs [ mo nth - 1]; }p r i vate static final Mo nth[] mo nt hs =

{ janu a r y, ..., december };. . .

}

*The previous art i c l e3 re f e rred to this as C lo ne a b le Va l u e, but the nameCopied Va l u e better captures the general intent of the pattern .

Page 4: Value Added

8 0 Java™Report | A P R I L 2 0 0 0 ht t p : / / w w w. j ava re po rt . co m

Patterns in Java / Kevlin He n n ey

object into and out of methods without permitting callersor called methods to affect the original object? Value objectsa re often used as attributes inside other objects. Subtle alias-ing problems can arise if the attribute is assigned dire c t l yf rom a method argument when it is set or if it is re t u rn e dd i rectly when queried:

O rder firs t O rde r, second O rde r ;. . .Date date = new Date(ye a r, mo nth, day);firs t O rde r. s e t D e l i ve r y D a t e ( d a t e ) ;d a t e. nex t D a y ( ) ;s e c o nd O rde r. s e t D e l i ve r y D a t e ( d a t e ) ;

In essence, this is a violation of encapsulation: Althoughd e c l a red private, users can still interf e re with the object’sre p re s e n t a t i o n .

So l u t i o n . Implement the C lo ne a b le i n t e rface or provide acopy constructor for the Value Class, and use a copy of theoriginal whenever it needs to be passed (see Listing 5). Thisp revents sharing and pre s e rves encapsulation, while stillallowing value objects to be modifie d .

For values that are queried far more often than they arem o d i fied, an I m mu t a b le Va l u e with a Mu t a b le Companiono ffers an alternative leading to less object cre a t i o n .

Immutable Va l u eD e fine a class for which instances have fixed state to avoidaliasing pro b l e m s .

Pro b l e m . How can you share Value Class objects and guar-antee no side effect problems? Copied Va l u e describes the conventions for using a modifiable value object tominimize aliasing issues. However, this can be erro rp rone and may lead to excessive creation of small objects, especially where values are frequently queriedor passed aro u n d .

If objects are shared between threads they must bet h read safe. Synchronization of state change incurs an over-head, but is essential in guarding against race conditions.Even where copying or synchronization are carefully attended to, there are still opportunities for undefined behavior: The integrity of an associative collection may bec o m p romised if the state of an object used as a key is

m o d i fied via an aliasing re f e re n c e .

So l u t i o n . Set the internal state of the Value Class object atc o n s t ruction, and allow no subsequent modifications; i.e.,p rovide only query methods and constructors, as shown inListing 6. Declaring the fields fin a l e n s u res this no-changep romise is honored. This guarantee implies also that eitherthe class itself must be fin a l or its subclasses must also beI m mu t a b le Va l u e s.

The absence of any possible state changes means thereis no reason to synchronize. Not only does this make I m-mu t a b le Va l u e objects implicitly thread safe, the absence oflocking means that their use in a threaded environment isalso effic i e n t .

Sharing of I m mu t a b le Va l u e objects is also safe and trans-p a rent in other circumstances; so, there is no need to copyan Immutable Value, and therefore no reason to implementCloneable. Attributes are changed by replacing their refer-enced I m mu t a b le Va l u e object with another holding a d i ff e rent value, rather than modifying the object that is already there.

T h e re are complementary techniques for creating I m-mu t a b le Va l u e objects: Provide a complete and intuitive setof constructors; provide a number of Class Fac tory Me t ho d s;or provide a Mu t a b le Companion.

Mutable Co m p a n i o nD e fine a companion class to simplify complex manipula-tion of I m mu t a b le Va l u e o b j e c t s .

Pro b l e m . How can you simplify complex construction ofan I m mu t a b le Va l u e? Constructors provide a way of cre a t-ing objects from a fixed set of arguments, but they cannotaccumulate changes or handle complex expressions with-out becoming too complex, e.g., calculate the date 15working days from today. Such re q u i rements typicallylead to expressions that create many temporary objects.

L I S T I N G 5 .

Passing a C o p ied Va l u e in and out of methods.class Orde r{

. . .public void setDeliveryDate(Date new D e l i ve r y D a t e )

{ de l i veryDate = (Date) new D e l i ve r y D a t e. c lo ne(); }public Date ge t D e l i ve r y D a t e ( )

{ return (Date) de l i ve r y D a t e. c lo ne(); }p r i vate Date de l i ve r y D a t e ;

}

L I S T I N G 6 .

D a t e ex p ressed as an I m mutable Va l u e.

public final class Date ...{

public Date(Year ye a r, Mo nth mo nth, int day){

t h i s. year = ye a r. ge t Va l u e ( ) ;t h i s. mo nth = mo nt h ;t h i s.day = day;

}public int ge t Year() { return year; }public Mo nth ge t Mo nth() { return mo nth; }public int ge t D a y I n Mo nth() { return day; }. . .p r i vate final int ye a r, day;p r i vate final Mo nth mo nt h ;

}

Page 5: Value Added

8 2 Java™Report | A P R I L 2 0 0 0 h t t p : / / w w w. j ava re po r t . co m

Class Fac tory Me t hods may be able to optimize some of thec reation and expressiveness issues, but they are still oneoff creation requests.

So l u t i o n . I m p l e m e n t a c o m p a n i o n c l a s s t h a t s u p p o rts m o d i fier methods and acts as a factory for I m mu t a b le Va l u e

objects. For convenience, the factory can stand not only asa separate class, but can also take on some of the roles andcapabilities of the I m mu t a b le Va l u e, e.g., S t r i ng B u f f e r a n dS t r i ng. The modifiers, which should be synchronized, allowfor cumulative or complex state changes, and a querymethod allows users to get access to the resulting I m mu t a b leVa l u e (see Listing 7).

Although it may support many of the same methods asits associated I m mu t a b le Va l u e, it is not related to it by in-heritance: It cannot fulfill the same guarantees on im-mutability and there f o re cannot be considered a subtype,hence its nonfamilial status as a companion. ■

Re fe re n ce s

1 . h t t p : / / c 2 . c o m / c g i / w i k i ? Va l u e O b j e c t.

2 . Gamma, E. et al., Design Patterns: Elements of Reusable Object-Oriented Software, Addison–We s l e y, 1995.

3 .H e n n e y, K., “Patterns of value,” Java Report, Vol. 5, No. 2,Feb. 2000, pp. 64–68.

4 . Cunningham, W., “The CHECKS Pattern Language of Infor-mation Integrity,” P a t t e rn Languages of Program Design, J.Coplien and D. Schmidt, Eds., Addison–We s l e y, 1995.

L I S T I N G 7 .

The D a t e Manipulator Mutable Companio n to D a t e.public class DateManipulator ...{

public sy nc h ronized void set(Year ye a r, Mo nth mo nth, int day)

{t h i s. year = ye a r ;t h i s. mo nth = mo nt h ;t h i s.day = day;

}public sy nc h ronized Date to D a t e ( )

{ return new Date(ye a r, mo nth, day); }public int ge t Year() { return ye a r. ge t Value(); }. . .p r i vate Year ye a r ;p r i vate Mo nth mo nt h ;p r i vate int day;

}

Patterns in Java / Kevlin He n n ey

column I’ll address the first, by showing how to explicitlydisable cloning for classes that have inherited a c lo nemethod with no checked exceptions.

The second trouble spot derives from a defect in the orig-inal design of the c lo ne method: It is not possible to cloneobjects through O b je c t re f e rences because the c lo ne m e t h o dis declared p ro t e c t e d in O b je c t and, furt h e rm o re, is notaccessible through the C lo ne a b le i n t e rface. Java’s designersopenly acknowledge the difficulties this imposes, stating,

“The sad fact of the matter is that C lo ne a b le is broken, andalways has been. The C lo ne a b le i n t e rface should have a pub-lic c lo ne method in it. This is a very annoying problem, andone for which there is no obvious fix . ”5

The inaccessibility of the c lo ne method via O b je c t re f e r-ences has implications for perf o rming deep copying on con-tainer objects. Generic O b je c t-based containers are pre v e n t e df rom cloning their elements because the c lo ne method is in-accessible. In the words of the Java language developersagain, “In fact, it’s nearly impossible to do deep copies inJava, as the C lo ne a b le i n t e rface lacks a public c lo ne o p e r a t i o n . ”4

J a v a ’s cloning mechanism has numerous defects and isunnecessarily awkward and error pro n e .1 Not only that, butcloning has been even more “broken” by the addition ofnew language features such as fin a l members and innerclasses, with apparent disre g a rd for their impact on a facil-ity that already presents a number of pro b l e m s .

Missing features in the language also make cloning morebothersome than it could be: Java does not support c o v a r i -ant re t u rn types, where an overriding method is perm i t t e d

to re t u rn a subclass of the type re t u rned by the method ito v e rrides. This re q u i res callers of the c lo ne method to castthe result to retrieve the type information that was lostwhen the c lo ne method re t u rn e d .

The c lo ne method is not supported for many common class-es for which it would be useful: notably S t r i ng and the wrap-per classes I nt e ge r, F lo a t, etc. Cloning instances of these classest h rough generic O b je c t re f e rences is unnecessarily irre g u l a r.

F o rt u n a t e l y, all these problems may be overcome. P roviding cloning support is an important part of designingclasses of maximum usefulness and re l i a b i l i t y. In a future col-u m n on cloning, I will present a mechanism that allows ob-jects to be cloned via O b je c t re f e rences, one that can be addedto any of the Java API container classes that will cause themto perf o rm a deep copy when cloned. You will then have allthe weaponry you need to beat Java at its own game. ■

Re fe re n ce s

1 . Ball, S., “Effective Cloning,” Java Report, Vol. 5, No. 1, Jan.2000, pp. 60–67.

2 . Ball, S. “Superc h a rged S t r i ngs,” Java Report, Vol. 4, No. 2,Feb. 1999, pp. 62–69.

3 . Gosling, J., B. Joy, and G. Steele, The Java Language Speci-fic a t i o n, Addison–We s l e y, 1996.

4. Sun Microsystems Bug Parade, h t t p : / / d e v e l o p e r. j a v a . s u n . -c o m / d e v e l o p e r / b u g P a r a d e / b u g s / 4 1 0 3 4 7 7 . h t m l.

5. h t t p : / / d e v e l o p e r. j a v a . s u n . c o m / d e v e l o p e r / b u g P a r a d e / -b u g s / 4 2 2 8 6 0 4 . h t m l.

6. Source code for the example classes, as well as the bench-marking application for timing the relative efficiency ofc o n s t ruction vs. cloning, is available at h t t p : / / e ff e c t i v e j a-v a . c o m / c o l u m n / d - c l o n i n g.

Continued from page 72

Effective Java / Steve Ba l l