3

This is an example of defensive copy in Effective java. Assume that scenario's in my underlying questions need a defensive copy, and cannot do with a comment asking client to avoid mutating objects passed in.

public Period(Date start, Date end) {
    this.start = new Date(start.getTime());
    this.end = new Date(end.getTime());
}

Questions:

  1. What to do if Date did not have a constructor to take itself in, to make my self more general, an object is passed with no mechanism to replicate itself, and such object does not belong to us, ie we cant change it in any way ?

  2. What if the constructor took type parameter as an argument, say Period(T object) and T could be mutable so needs defensive copy. We dont have any idea of what is T. How to do defensive copy in this case ?

  3. What is an interface is passed where some of its subclasses do have a constructor like Date to create an object of itself and some of its subclasses dont have any mechanism to do so ?

  4. How deep should we defensively copy ? Lets say we copy an array, but array elements were mutable ?

JavaDeveloper
  • 5,320
  • 16
  • 79
  • 132
  • I would say in some cases that this situation becomes a code smell. For an object that complicated, it means you're preserving state somewhere, and I would consider eliminating that state preservation. That's not the right thing to do in all cases, but it is a question that should be raised in any of those situations. As for when you really do need to do this, I would say you're forced to hand write custom copying code or define some kind of new small, immutable object that only copies the data it actually needs. – jpmc26 Jan 09 '14 at 08:07
  • 1
    Bear in mind that these aren't strict universal rules. It all depends on the situation. You shouldn't go out of your way to copy all the parameters (I would reject your code on that basis), and when you can't well, either change the code (if it really needs to be an immutable object) or let it be. – Kayaman Jan 09 '14 at 08:09
  • Also you should check if the start and end date is null. If you don't do this you could get a NullPointerException. – Danny Gloudemans Jan 09 '14 at 08:29
  • @Gynnad: if the dates are mandatory, throwing a NullPointerException is the right thing to do. – JB Nizet Jan 09 '14 at 10:24

3 Answers3

2
  1. If all its state is available, you can extract its state and construct a new object by yourself. Otherwise, you can't do anything about it except using nasty reflection or serialization tricks.
  2. If T is not an instance of a class that allows copying itself, you can't do anything.
  3. You can't do anything about it.
  4. It depends.

By reading your question, it looks like you would like to apply the "defensive copy" advice everywhere. You shouldn't. Most of the time, code using mutable objects want a reference to the original object, and not a copy. Especially if what you get as argument is an instance of an abstract class or interface.

You're forced to make a defensive copy of Date because it's mutable value type that shouldn't be mutable, and wouldn't be if it had been properly designed. If you promote immutability for value types, then defensive copies become unnecessary. For non-value types, you generally don't want a copy, but a reference to the object.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
0
  1. If you can't change object's state anyway, you don't need a defensive copy.
  2. The only thing you can do is assume probable implementation of T and check them with instanceOf.
  3. Same as 2.
  4. At your discretion. If you assume that modification of array elements could break your program in another places, you should copy them all too.
PKopachevsky
  • 262
  • 1
  • 6
0

Defensive programming matters when the objects you pass to a method is mutable. A good practice (also described in the Effective Java book) is to make them immutable.

  1. If the Date class is not final, you can write a wrapper class for it, that is subclass of Date.
  2. It depends. Probably, there will be no need to clone it.
  3. It shouldn't bother you. The implementor of an interface should take care of synchronization issues. Generally, it is a good practice to pass interfaces instead of their implementations.
  4. For standard java collections there are a lot of utility methods in the java.util.Collections class, such as unmodifiableList and unmodifiableMap, intended to use for defensive programming.
Alexander Tokarev
  • 2,743
  • 2
  • 20
  • 21
  • This advice sounds great in theory, but in real life, implementing my own `Date` wrapper is rather cumbersome. And I'm not sure how the last 2 make sense for this question. The `unmodifiableX` methods would have to be used outside your class; they're useless as a defensive copy mechanism since the underlying object could be modified outside your class. They're intended to keep other objects from modifying data your code generates, which is somewhat the reverse of defensive copying. Synchronization is a different problem than defensive copying. (Just explaining my downvote.) – jpmc26 Jan 10 '14 at 23:23