Search code examples
javaeffective-javadefensive-programming

What is the best way of sending defensive copy of data ?


I just have read effective java rule 39 (Defensive Copy). It is not told explicitly, two times of copy should occur every data transaction to follow this rule. Below is the example code I thought. It seems somewhat redundant. Am I understand it correctly ? Is there any better way ?

public class SomeClass {

    private MyData myData; 

    SomeClass() {
        myData = new MyData("1");
    }

    public MyData getData() {
        return new MyData(myData); // 1st Copy of data
    }

    public static void main(String[] args) {
        SomeClass someClass = new SomeClass();
        OtherClass otherClass = new OtherClass(someClass.getData()); //Pass data which is invariant
    }
}

class OtherClass {

    MyData myData; 

    OtherClass(MyData data) {
        myData = new MyData(data);  // 2nd Copy of data
    }
}

class MyData {
    private String name;
    public MyData(String name) { this.name = name; }
    public MyData(MyData data) { this.name = data.name; }
    public void setName(String name) { this.name = name; }
}

Solution

  • Your understanding is correct, both the constructor and the method make defensive copies of MyData. They do it for slightly different reasons, discussed below.

    There are two reasons to make a defensive copy:

    1. Protect from modifications of incoming data - The caller passes you an object, and decides to change it later. Since you've made a defensive copy of it, the changes the caller makes have no effect on the data that you store internally, and
    2. Protect from modifications of outgoing data - The caller may decide to change an object received from one of your methods. Since you've returned a defensive copy of your object, your internal data remains safe.

    The code demonstrates both situations - OtherClass(MyData data) constructor demonstrates issue #1, while MyData getData() demonstrates issue #2.

    Note that defensive copies are required only because of the decision to make MyData class mutable (i.e. giving it a setName method). There is no need to make defensive copies of objects of immutable classes.