Java Tip #1: Defensive copies

Something that could easily be missed when programming in Java is inadvertently exposing the internals of a supposedly encapsulated field to clients of your class. Consider the following naive implementation of a rectangle class that disallows negative dimensions:

public final class MyRectangle {
private final Dimension dim;

public MyRectangle(Dimension dim) {
if( dim.height < 0 || dim.width < 0 ) {
throw new IllegalArgumentException("Dimensions cannot be negative");
}

this.dim = dim;
}

public int getArea() {
return dim.height * dim.weight;
}
}

A cursory glance may seem indicate that the class should be immutable and no negative dimensions, and thus no negative areas, are possible. Not true. Consider this bit of code that uses the MyRectangle class:

Dimension dim = new Dimension(2, 3);
MyRectangle rect = new MyRectangle(dim);
dim.setSize(-3, 4); // modifies rect's internal Dimension field!

This is possible because Dimension is a mutable class! Therefore, it is important to make a defensive copy of each parameter to the constructor that is mutable. We can fix the MyRectangle class by changing it’s constructor like so:

public MyRectangle(Dimension dim) {
this.dim = new Dimension(dim); // make defensive copy

if( dim.height < 0 || dim.width < 0 ) {
throw new IllegalArgumentException("Dimensions cannot be negative");
}
}
Notice how a copy of the Dimension parameter is made, so that the client has no reference (and thus no access) to the internal dim field of the MyRectangle object. The same has to be done in the case where accessors return mutable fields - make sure to return defensive copies. The rule is never to directly return the internal field to a client class - always create a defensive copy and return that instead, so that there is no handle into the object internals.

5 Comments & TrackBacks ()

The paper doll icon that precedes each comment is an idea conceived by Vanessa Tan.

Paper doll icon
Mats Henricson's Gravatar

What you’re saying about defensive copies makes perfect sense, from a theoretical standpoint, but I have never ever seen a bug where not creating a defensive copy have caused a bug. Have you?

Posted by: Mats Henricson on June 17, 2003 6am

Paper doll icon
Cheah Chu Yeow's Gravatar

I don’t quite understand what you’re saying. Allowing an internal (private) field to be accessible and modifiable from outside the object itself breaks the rule of encapsulation and could cause errors and exceptions - consider a possible case of an internal Date field being set to a Jan 1, 1970 outside the encapsulating object and then used in a date calculation to find the period between 2 Dates. You’d get a totally unexpected result.

I haven’t seen a bug due to not making defensive copies in commercial or Open Source projects, since I do not often read bug reports, but I assure you I’ve seen bugs due to this in projects I’ve been part of, or have had the chance to use.

Posted by: Cheah Chu Yeow on June 17, 2003 2pm

Paper doll icon
adam connor's Gravatar

This is an example of why I wish I could return constant references, as in C++. Cloning can be a very expensive way of protecting state.

Posted by: adam connor on June 21, 2003 2pm

Paper doll icon
vlad's Gravatar

What’s the point of publishing tips that have been covered in tens of articles and books by now?

Posted by: vlad on June 22, 2003 2am

Paper doll icon
Yining's Gravatar

It’s good to be defensive when coding, however, I think in this particular example, it should be the Dimension class’ responsibility to make sure it doesn’t get negative dimension values.

Of course, that argument does not apply in the context in which Dimension class implementation is out of the control by the person/team implements MyRectangle class.

Posted by: Yining on June 26, 2003 9pm

You can subscribe to the RSS feed for comments on this post.

Sorry, this entry is no longer accepting comments. If you have something you really want to say, you can write me.