unmodifiableList() 方法用于返回指定列表的不可修改视图。

    在《重构——改善既有代码的设计》一书中,有一种重构手法叫Encapsulate Collection(封装集群),为了演示该重构手法,我写了四个类,通过对比重构前后的代码,加深对这一重构手法的理解。

    类Student有一ArrayList属性,如果没有阅读《重构——改善既有代码的设计》一书,很多人可能会像我一样,如下设计类Student。但是,如果通过Student.getCourses()获得对ArrayList属性引用后,就可以任意为Student对象添加“课程”,而Student对象对此一无所知,这不符合面向对象编程的习惯。

    1. package com.readonlylist;
    2. import java.util.ArrayList;
    3. public class Student{
    4. private String name;
    5. private ArrayList<String> courses;
    6. public Student(String name, ArrayList<String> courses){
    7. this.name = name;
    8. this.courses = courses;
    9. }
    10. public ArrayList<String> getCourses(){
    11. return courses;
    12. }
    13. public void setCourses(ArrayList<String> courses){
    14. this.courses = courses;
    15. }
    16. public String getName(){
    17. return name;
    18. }
    19. public void setName(String name){
    20. this.name = name;
    21. }
    22. }
    1. package com.readonlylist;
    2. import java.util.ArrayList;
    3. public class Test{
    4. public static void main(String[] args) {
    5. ArrayList<String> list = new ArrayList<String>();
    6. list.add("001");
    7. list.add("002");
    8. Student s = new Student("Tom", list);
    9. ArrayList<String> anotherList = s.getCourses();
    10. anotherList.add("999");
    11. System.out.println("Tom's course.length = " + s.getCourses().size());
    12. }
    13. }

    重构后的Student类如下所示:

    1. package com.readonlylist;
    2. import java.util.ArrayList;
    3. import java.util.Collections;
    4. import java.util.List;
    5. public class Student1{
    6. private String name;
    7. private ArrayList<String> courses;
    8. public Student1(String name, ArrayList<String> courses){
    9. this.name = name;
    10. this.courses = courses;
    11. }
    12. public String getName(){
    13. return name;
    14. }
    15. public void setName(String name){
    16. this.name = name;
    17. }
    18. public void addCourse(String course){
    19. courses.add(course);
    20. }
    21. public String removeCourse(String course){
    22. boolean removed = courses.remove(courses);
    23. if (removed){
    24. return course;
    25. }else{
    26. return null;
    27. }
    28. }
    29. public List<String> getCourses(){
    30. return Collections.unmodifiableList(courses);
    31. }
    32. }
    1. package com.readonlylist;
    2. import java.util.List;
    3. import java.util.ArrayList;
    4. public class Test1{
    5. public static void main(String[] args){
    6. ArrayList<String> list = new ArrayList<String>();
    7. list.add("001");
    8. list.add("002");
    9. Student1 s = new Student1("Tom", list);
    10. List<String> anotherList = s.getCourses();
    11. /**
    12. * throws java.lang.UnsupportedOperationException
    13. * should replace with s.addCourse(String course)
    14. */
    15. anotherList.add("999");
    16. // never reached
    17. System.out.println("Tom's course.length = " + s.getCourses().size());
    18. }
    19. }

    重构后,Student1类,仅对外提供的getCourses()方法,而没有setCourses()方法,而且通过getCourses()方法获得的courses是“只读的”,如果你试图向其添加一个新课程,则抛出java.lang.UnsupportedOperationException。你必须通过Student1.addCourse()来向特定的Student1对象添加一个新课程。就好像,你必须让顾客自己向购物车里放食物,而不能在顾客毫不知情下,偷偷向其购物车里放食物。