Jdk中的Collections.unmodifiable与使用
场景:你去购物时被人偷偷往你购物车里丢了东西
需求:
我们的需求是只有在创建对象(学生)时,才能设定ta的课程,所以我们在设计类时,只用了get方法
即:
public List getCources() {
return cources;
}
并未给ta setCources的权限,就是不希望外部程序可以在任何拿到学生对象时都可以任意往课程list中添加元素,只能在声明时一次性的加到初始化中, 如果用final就只能每次都只能用初始化的值,final在声明时就必须赋值,也无法解决我们的要求,所以我们需要改造一下getXX方法,将此集合设置为不可变集合,即除了通过构造器外,不能在任何其它地方进行赋值
就好比你只能让学生自己选择课程,即在初始化时直接选好课程,而不能在学生不知道的情况下随便偷偷的通过setXXX往里面加课程,也不能把人家选好的课程直接删除不给人家上了,所以需要进行控制
//这是我们的类Student类,并没有set方法
class Student{
private String sid;
private String sname;
private List<Course> cources;
public Student(){
}
public Student(String sid, String sname, List<Course> cources) {
this.sid = sid;
this.sname = sname;
this.cources = cources;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public List<Course> getCources() {
return cources;
}
@Override
public String toString() {
return "Student{" +
"sid='" + sid + '\'' +
", sname='" + sname + '\'' +
", cources=" + cources +
'}';
}
static class Course {
private String cid;
private String cname;
public Course(String cid, String cname) {
this.cid = cid;
this.cname = cname;
}
public Course() {
}
public String getCid() {
return cid;
}
public void setCid(String cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
@Override
public String toString() {
return "Course{" +
"cid='" + cid + '\'' +
", cname='" + cname + '\'' +
'}';
}
}
当我们开始调用时:
@Test
public void testAddStudent() {
//初始化
List<Student.Course> courses = new ArrayList<Student.Course>();
courses.add(new Student.Course("1","语言"));
courses.add(new Student.Course("2","数学"));
courses.add(new Student.Course("3","英语"));
Student stu = new Student("101", "徐睿 ", courses);
//非预期1:此处即你正在排除结账时,结果人家偷偷往你购物车了丢了一大堆东西
stu.getCources().add(new Student.Course("3", "计算机"));
stu.getCources().add(new Student.Course("4","机器学习"));
//非预期2:此处类似于我们选好的东西,被人直接把我们蓝子里的东西拿掉了
stu.getCources().remove(0);
System.out.println(stu);
}
代码出现了我们不希望看到的结果 :
stu.getCources().add(new Student.Course("3", "计算机")); stu.getCources().add(new Student.Course("4","机器学习"));
在我们没有提供set的时候,还是被外部进行了修改:即偷偷在我们不知情的时候改了我们的课程,就好比你去购物时被人偷偷往你购物车里丢了东西。
既然别要可以往我们篮子里放东西,也就意味着ta可以往我们篮子里拿东西,你会发现:
stu.getCources().remove(0);
类似的情况还有好多,我们明明已经禁止了别人操作我们的属性了,还是无法避免在外部调用时意外去修改我们的内容,所以我们需要用防御式的编程方式,禁止外部的操作影响到我们构造器里的东西。
还好jdk帮我们考虑到了:
解决方法:不可变集合:Collections.unmodifiableXXX
所以可以将getCourses改为:
public List<Course> getCources() {
return cources == null ? null : Collections.unmodifiableList(cources);
}
//这样如果你再执行下面的代码时:
stu.getCources().add(new Student.Course("3", "计算机"));
stu.getCources().add(new Student.Course("4","机器学习"));
//此处直接把我们蓝子里的东西拿掉了
stu.getCources().remove(0);
output:-----------------------------------------
com.ryan.pub.readonlylist.TestStudent,testAddStudent
java.lang.UnsupportedOperationException
如此,当别人再往里放东西时就会报错了,Jdk为我们所有的集合提供了一整套的Collections.unmodifiableXXX方法,可以供我们使用以解决类似的问题
完整代码如下:
package com.ryan.pub.readonlylist;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class TestStudent {
@Test
public void testAddStudent() {
//初始化
List<Student.Course> courses = new ArrayList<Student.Course>();
courses.add(new Student.Course("1","语言"));
courses.add(new Student.Course("2","数学"));
courses.add(new Student.Course("3","英语"));
Student stu = new Student("101", "徐睿 ", courses);
//以下两行是非法代码,不允许在外部被随意修改,只可以在构造器中完成
stu.getCources().add(new Student.Course("3", "计算机"));
stu.getCources().add(new Student.Course("4","机器学习"));
System.out.println(stu);
}
}
class Student{
private String sid;
private String sname;
private List<Course> cources;
public Student(){
}
public Student(String sid, String sname, List<Course> cources) {
this.sid = sid;
this.sname = sname;
this.cources = cources;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public List<Course> getCources() {
return cources == null ? null : Collections.unmodifiableList(cources);
}
@Override
public String toString() {
return "Student{" +
"sid='" + sid + '\'' +
", sname='" + sname + '\'' +
", cources=" + cources +
'}';
}
static class Course {
private String cid;
private String cname;
public Course(String cid, String cname) {
this.cid = cid;
this.cname = cname;
}
public Course() {
}
public String getCid() {
return cid;
}
public void setCid(String cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
@Override
public String toString() {
return "Course{" +
"cid='" + cid + '\'' +
", cname='" + cname + '\'' +
'}';
}
}
}