Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
306 views
in Technique[技术] by (71.8m points)

immutability - Java, Making a class Immutable

I came across this exercise online where I have two classes and I'm supposed to make the Tutor class immutable. However, the only thing I can think of is adding final to name field. When it comes to the constructor, I don't think I need to change the initialisation of the name variable as String is immutable. I'm not sure how to approach the collection and how to make this part of the constructor immutable. According to the exercise, I'm not supposed to change the Student class (which I can see is mutable)

public class Student {    
    private String name;
    private String course;

    public Student(String name, String course) {    
        this.name = name;
        this.course = course;    
    }

    public String getName() {
        return name;
    }

    public String getCourse() {
        return course;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setCourse(String course) {
        this.course = course;
    }
}

public final class Tutor {
    private String name;
    private final Set<Student> tutees;

    public Tutor(String name, Student[] students) {
        this.name = name;
        tutees = new HashSet<Student>();
        for (int i = 0; i < students.length; i++)
            tutees.add(students[i]);
    }

    public Set<Student> getTutees() {
        return Collections.unmodifiableSet(tutees);
    }

    public String getName() {
        return name;
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The Tutor class presents many aspects promoting its immutability :

  • the class is final
  • the Set<Student> is protected against the modifications
  • no method allowing to change directly the state of the class

However, the defensive copy of the constructor is not complete.
It also has to copy the Students elements of the array passed. Otherwise the client of the constructor may change any instance of them and make so the Tutor instance mutable such as :

Student[] students = ...;
Tutor tutor = new Tutor(name, students);
students[0].setName("new Name!"); // break the immutability of Tutor

You should write something like :

public Tutor(String name, Student[] students){
  this.name = name;
  tutees = new HashSet<Student>();
  for (Student student : students){   
      Student copy = new Student(student.getName(), 
                                    student.getCourse());
      tutees.add(copy);
   }     
}

Additionally note that the Set returned by getTutees() is unmodifiable but elements contained in are as Student is mutable. So to make Tutor immutable you also have to create a copy of the Student elements as you return getTutees() such as :

public Set<Student> getTutees(){
   Set<Student> students = new HashSet<>();
   for (Student student : tutees){
      Student copy = new Student(student.getName(), 
                                    student.getCourse());
      students.add(copy);
   }     
   return Collections.unmodifiableSet(students);
}

As you may notice, getting the immutability in these conditions (an instance that we wish immutable but that contains a collection referencing mutable instances) requires to write more code (to read/to maintain/to test) and to perform more processing (so slower to execute).
If Student was an immutable class, the original getTutees() and the original constructor would be enough.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...