Collections.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 reached
        System.out.println("Tom‘s course.length = " + s.getCourses().size());        
    }
}

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

时间: 2024-12-21 14:57:21

Collections.unmodifiableList方法的使用与场景的相关文章

Collections.unmodifiableMap,Collections.unmodifiableList,Collections.unmodifiableSet作用及源码解析

在文章:Mybatis源码解析,一步一步从浅入深(五):mapper节点的解析中mybatis的源码中用到了Collections.unmodifiableList方法,其实还有unmodifiableMap,unmodifiableSet两个相似的方法,接下来就分析一下. unmodifiableMap,unmodifiableList,unmodifiableSet都是Collections的静态方法.可以明显看到三个方法都是unmodifiable开始的. unmodifiable的中文意

java中unmodifiableList方法的应用场景

java对象中primitive类型变量可以通过不提供set方法保证不被修改,但对象的List成员在提供get方法后,就可以随意add.remove改变其结构,这不是希望的结果.网上看了下,发现Collections的静态方法unmodifiableList可以达到目的.方法原型为:public static <T> List<T> unmodifiableList(List<? extends T> list);用法也很简单,传入一个List实例la,返回这个list

由Collections.unmodifiableList引发的重构

今天阅读源码的时候,无意中看到了Collections.unmodifiableList的用法,因为以前没有这样做过,所以查询了他的API,是这样写的 public static <T> List<T> unmodifiableList(List<? extends T> list) 参数:list--这是一个不可修改视图是要返回的列表中. 返回值:在方法调用返回指定列表的不可修改视图. 1.用法探讨: 1 public class CollectionsListDem

java.util.Collections.copy()方法注意点

今天发现单独的将一个ArrayList的对象添加到另外一个ArrayList的时候,总是源列表和目的列表相同的内存地址.原因如下: 偶然看到了Collections的copy(List desc,List src)方法.当时就想这个方法和初始化一个List desc = new  ArrayList(List c)[参数必须实现Collection接口]的区别. 两者的差别很大,后者是一个浅拷贝,只是对源list的元素进行拷贝,拷贝的只是引用.拷贝后两个list的元素(引用)不同,但是引用所指向

java.util.Collections.synchronizedSet()方法的使用

下面的例子显示java.util.Collections.synchronizedSet()方法的使用 package com.; import java.util.*; public class CollectionsDemo { public static void main(String[] args) { // create set Set<String> set = new HashSet<String>(); // populate the set set.add(&q

Java8集合框架——集合工具类Collections内部方法浅析

本文的目录结构: 零:Collections 的官方注释 一.Algorithms(算法类操作) 01.排序 sort 02.二分查找 binarySearch 03.列表反转 reverse 04.元素重排列 shuffle 05.元素交换 swap 06.列表填充 fill 07.元素复制 copy 08.最小/最大元素查找 min/max 09.数组旋转 rotate 10.元素替换 replaceAll 11.子列表匹配 二.Unmodifiable Wrappers(不可变包装类) 三

考虑用静态工厂方法代替构造器的场景

总结点,使用场景: a.当你尝试使用多个构造器,然后,每个构造器的区别是签名(参数类型或者参数顺序不同或者参数数量不同),那么,这个时候,可以考虑使用静态工厂方法来替代构造器.“如果构造器的参数本身没有确切地描述正被返回的对象,那么具有适当名称的静态工厂会更容易使用,产生的客户端代码也更易于阅读” Example: BigInteger.probablePrime()返回一个素数的整数 相比构造器Biginteger(int, int, Random)要直观 Car.smallCar()返回小车

Collections.sort方法对list排序的两种方式

Collections.sort( )分为两部分,一部分为排序规则,一部分为排序算法 . 规则用来判断对象,算法则考虑如何进行排序 对于自定义对象,sort()不知道规则,所以无法比较,这种情况下一定要定义排序规则.方式有两种: 第一种,java.lang下面的一个接口:Comparable.可以让自定义对象实现一个Comparable接口,这个接口只有一个方法comparableTo(Object o) 其规则是当前对象与o对象进行比较,返回一个int值,系统根据此值进行排序. 如当前对象>o

Java基础集锦——利用Collections.sort方法对list排序

要想对List进行排序,可以让实体对象实现Comparable接口,重写compareTo方法即可实现按某一属性排序,但是这种写法很单一,只能按照固定的一个属性排序,没变法变化.通过下面这种方法,可以动态的指定List按照某一个属性进行排序,例子很简单,看代码就明白了. import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; publ