unmodifiableList() 方法用于返回指定列表的不可修改视图。
在《重构——改善既有代码的设计》一书中,有一种重构手法叫Encapsulate Collection(封装集群),为了演示该重构手法,我写了四个类,通过对比重构前后的代码,加深对这一重构手法的理解。
类Student有一ArrayList属性,如果没有阅读《重构——改善既有代码的设计》一书,很多人可能会像我一样,如下设计类Student。但是,如果通过Student.getCourses()获得对ArrayList属性引用后,就可以任意为Student对象添加“课程”,而Student对象对此一无所知,这不符合面向对象编程的习惯。
package com.readonlylist;import java.util.ArrayList;public class Student{private String name;private ArrayList<String> courses;public Student(String name, ArrayList<String> courses){this.name = name;this.courses = courses;}public ArrayList<String> getCourses(){return courses;}public void setCourses(ArrayList<String> courses){this.courses = courses;}public String getName(){return name;}public void setName(String name){this.name = name;}}
package com.readonlylist;import java.util.ArrayList;public class Test{public static void main(String[] args) {ArrayList<String> list = new ArrayList<String>();list.add("001");list.add("002");Student s = new Student("Tom", list);ArrayList<String> anotherList = s.getCourses();anotherList.add("999");System.out.println("Tom's course.length = " + s.getCourses().size());}}
重构后的Student类如下所示:
package com.readonlylist;import java.util.ArrayList;import java.util.Collections;import java.util.List;public class Student1{private String name;private ArrayList<String> courses;public Student1(String name, ArrayList<String> courses){this.name = name;this.courses = courses;}public String getName(){return name;}public void setName(String name){this.name = name;}public void addCourse(String course){courses.add(course);}public String removeCourse(String course){boolean removed = courses.remove(courses);if (removed){return course;}else{return null;}}public List<String> getCourses(){return Collections.unmodifiableList(courses);}}
package com.readonlylist;import java.util.List;import java.util.ArrayList;public class Test1{public static void main(String[] args){ArrayList<String> list = new ArrayList<String>();list.add("001");list.add("002");Student1 s = new Student1("Tom", list);List<String> anotherList = s.getCourses();/*** throws java.lang.UnsupportedOperationException* should replace with s.addCourse(String course)*/anotherList.add("999");// never reachedSystem.out.println("Tom's course.length = " + s.getCourses().size());}}
重构后,Student1类,仅对外提供的getCourses()方法,而没有setCourses()方法,而且通过getCourses()方法获得的courses是“只读的”,如果你试图向其添加一个新课程,则抛出java.lang.UnsupportedOperationException。你必须通过Student1.addCourse()来向特定的Student1对象添加一个新课程。就好像,你必须让顾客自己向购物车里放食物,而不能在顾客毫不知情下,偷偷向其购物车里放食物。
