Java不可变集合Immutable

为什么需要不可变集合

  • 在并发程序中,使用不可变集合保证线程安全。尤其当一个对象是值对象时,更应该考虑采用Immutable方式;
  • 被不可信的类库使用时会很安全;
  • 对象不支持修改操作,将会节省空间和时间的开销。所有不可变的集合实现都比可变集合更加有效地利用内存;
  • 可以当作一个常量来对待,并且这个对象在以后也不会被改变。
  • 使用Immutable是一个防御性编程技术。 

1. Collections.unmodifiableList(…):不是真正的不可变集合

在JDK类库中很多集合(List、Set、Map等)都可以调用Collections类提供的静态方法unmodifiableXXX(…)来得到一个不可修改的视图 ,但是JDK实现的不是真正的不可变集合,当原始集合被修改后,不可变集合里面的元素也是跟着发生变化。

2. Guava提供的Immutable:真正的不可变集合

从下面的例子了解 1 和 2 差别:

public class Student {
    private String name;

    /** 课程编号 */
    private List<String> courses;

    public Student(String name, List<String> courses) {
        this.name = name;
        this.courses = courses;
    }

    public String getName() {
        return name;
    }

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

    public List<String> getCourses() {
        // JDK不可变集合
        return Collections.unmodifiableList(courses);
    }

    public void addCourses(String course) {
        this.courses.add(course);
    }

    public String removeCourses(String course) {
        boolean removed = this.courses.remove(course);
        if (removed) {
            return course;
        }
        return null;
    }
}

---------- 测试场景①:

public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("001");
        list.add("002");

        Student student = new Student("Tom", list);
        // 修改集合前的打印
        System.out.println("----- Tom's course list-----");
        list.forEach(System.out::println);

        List<String> courseList = student.getCourses();
        courseList.add("003");
}

执行结果:

----- Tom's course list-----
001
002
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.util.Collections$UnmodifiableCollection.add(Collections.java:1055)
	at com.dnl.learning.test.demo.unmodifiable.TestList.main(TestList.java:19)

 list集合不可变,向集合添加元素会抛出异常。

---------- 测试场景②:

public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("001");
        list.add("002");

        Student student = new Student("Tom", list);
        // 修改集合前的打印
        System.out.println("----- 修改集合前的打印 list-----");
        list.forEach(System.out::println);

        List<String> courseList = student.getCourses();
        System.out.println("----- 修改集合前的打印 courseList-----");
        courseList.forEach(System.out::println);
        // courseList.add("003");

        // TODO 修改list本身
        list.add("004");
        // 修改集合后的打印
        System.out.println("----- 修改集合后的打印 list-----");
        list.forEach(System.out::println);
        System.out.println("----- 修改集合后的打印 courseList-----");
        courseList.forEach(System.out::println);
}

执行结果:

----- 修改集合前的打印 list-----
001
002
----- 修改集合前的打印 courseList-----
001
002
----- 修改集合后的打印 list-----
001
002
004
----- 修改集合后的打印 courseList-----
001
002
004

 通过改变原集合,Java不可变Immutable集合被修改。

 修改实体类的 getCourses() 方法:

  public List<String> getCourses() {
        // return Collections.unmodifiableList(courses);
        return ImmutableList.copyOf(courses);
  }

测试场景2再执行一遍,courseList集合里面的元素个数没有改变。

----- 修改集合前的打印 list-----
001
002
----- 修改集合前的打印 courseList-----
001
002
----- 修改集合后的打印 list-----
001
002
004
----- 修改集合后的打印 courseList-----
001
002

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值