3

why we must do Defensive Copying in order to achieve Immutable class? Look at this code:

public final class EmailMessage   {
    private final String from;
    private final String to;
    private final String message;
    private final Date   date;

    public EmailMessage( String from, String to, String msg, Date date )
    {
        this.to = to;
        this.from = from;
        this.message = msg;
        this.date = new Date(date.getTime());// instead of date;
    }

    public String getFrom()
    {
        return( from );
    }

    public Date getDate() {
        return( new Date( date.getTime() ); // instead of Date
    }
}

Why it won't be Immutable if we didn't do Defensive Copying?

Raedwald
  • 46,613
  • 43
  • 151
  • 237
MaxDevelop
  • 637
  • 1
  • 4
  • 16
  • 4
    because `Date` class is mutable, even if you declare its instance final, value still can be altered by `setDay()` and other setters. Copying `date` from constructor argument you cannot guarantee that references won't be kept in outer code thus making it possible to change. – Alex Salauyou Apr 01 '15 at 08:41
  • This bad design problem is solved in `java.util.time` package in Java 8, where you should use `LocalDate`, `LocalTime` and other classes that are all fully immutable and safe. – Alex Salauyou Apr 01 '15 at 08:46
  • you can use jodatime to remove design issues or java.util.time (from Java 8) – ha9u63a7 Apr 01 '15 at 09:34

2 Answers2

4

In order to achieve immutability you must make copies of all mutable objects passed into your constructor, and also return copies for all mutable objects stored inside your class, if any.

  • If you do not make a copy of the date passed into you, the caller can change the date after your object has been constructed, effectively mutating it.
  • If you do not return a copy from a getter of a mutable object, the callers can mutate the object that they get from you, effectively mutating your object as well.

In your specific example, Date class is mutable. If yo skip copying in the constructor, malicious code can do this:

Date d = new ...
EmailMessage msg = new EmailMessage("lazy dog", "quick brown fox", "Jump!", d);
d.setTime(d.getTime()+12345); // Changes the date inside msg

If you skip the second copy, the callers can do this:

EmailMessage msg = ...
Date d = msg.getDate();
d.setTime(d.getTime()+12345); // Changes the date inside msg
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
2

Because otherwise it is possible to change the object state. Let's imagine, that your getDate method is the following:

public Date getDate() {
    return date; // instead of Date
}

And we use it in the following way:

EmailMessage msg = new EmailMessage(...); // initialization
Date date = msg.getDate();
date.setTime(...); //ooops, our msg object has another date now
nikis
  • 11,166
  • 2
  • 35
  • 45