java并发编程——不可变对象

非 Y 不嫁゛ 提交于 2019-12-03 20:53:16

不可变类

不可变类:指这个类的实例一旦创建完成后,就不能改变其成员变量值。如JDK内部自带的8个包装类和String类都是不可变类(Interger、Long和String等)都是不可变类。所以不可变类并不是指该类是被final修饰的,而是指该类的所有属性是被final修饰的

可变类:相对于不可变类,可变类创建实例后可以改变其成员变量值,开发中创建的大部分类都属于可变类。

java中自定义不可变类应该遵守如下原则:

  1. 使用private和final修饰符来修饰该类的属性。
  2. 提供带参数的构造器,用于根据传入的参数来初始化属性。
  3. 仅为该类属性提供getter方法,不要提供setter方法。
  4. 如果有必要,重写hashCode和equals方法,同时应保证两个用equals方法判断为相等的对象,其hashCode也应相等。

使用不可变类的好处?

  1. Immutable对象是线程安全的,可以不用被synchronize就在并发环境中共享
  2. Immutable对象简化了程序开发,因为它无需使用额外的锁机制就可以在线程间共享
  3. Immutable对象提高了程序的性能,因为它减少了synchroinzed的使用
  4. Immutable对象是可以被重复使用的,你可以将它们缓存起来重复使用,就像字符串字面量和整型数字一样。你可以使用静态工厂方法来提供类似于valueOf()这样的方法,它可以从缓存中返回一个已经存在的Immutable对象,而不是重新创建一个。

immutable对象也有一个缺点就是会制造大量垃圾,由于他们不能被重用而且对于它们的使用就是”用“然后”扔“,字符串就是一个典型的例子,它会创造很多的垃圾,给垃圾收集带来很大的麻烦。当然这只是个极端的例子,合理的使用immutable对象会创造很大的价值。

不可变集合

1、JDK中实现immutable集合

在JDK中提供了Collections.unmodifiableXXX系列方法来实现不可变集合, 而jdk对不可变集合是通过抛出异常来实现的。但是存在一些问题,下面我们先看一个具体实例:

public class ImmutableTest {

    @Test
    public void testJDKImmutable(){
        List<String> list=new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("c");

        //通过list创建一个不可变的unmodifiableList集合
        List<String> unmodifiableList=Collections.unmodifiableList(list);
        System.out.println(unmodifiableList);

        //通过list添加元素
        list.add("ddd");
        System.out.println("往list添加一个元素:"+list);
        System.out.println("通过list添加元素之后的unmodifiableList:"+unmodifiableList);

        //通过unmodifiableList添加元素
        unmodifiableList.add("eee");
        System.out.println("往unmodifiableList添加一个元素:"+unmodifiableList);

    }
}

··············································································
运行结果:
[a, b, c]
往list添加一个元素:[a, b, c, ddd]
通过list添加元素之后的unmodifiableList:[a, b, c, ddd]

java.lang.UnsupportedOperationException
    at java.util.Collections$UnmodifiableCollection.add(Collections.java:1055)
    at dawn.thread.ImmutableTest.testJDKImmutable(ImmutableTest.java:31)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

通过运行结果我们可以看出:虽然unmodifiableList不可以直接添加元素,但是我的list是可以添加元素的,而list的改变也会使unmodifiableList改变。

所以说Collections.unmodifiableList实现的不是真正的不可变集合。

2、Guava的immutable集合

Guava提供了对JDK里标准集合类里的immutable版本的简单方便的实现,以及Guava自己的一些专门集合类的immutable实现。当你不希望修改一个集合类,或者想做一个常量集合类的时候,使用immutable集合类就是一个最佳的编程实践。

注意:每个Guava immutable集合类的实现都拒绝null值。我们做过对Google内部代码的全面的调查,并且发现只有5%的情况下集合类允许null值,而95%的情况下都拒绝null值。万一你真的需要能接受null值的集合类,你可以考虑用Collections.unmodifiableXXX。

immutable集合可以有以下几种方式来创建:

  1. 用copyOf方法, ImmutableSet.copyOf(set)
  2. 使用of方法,ImmutableSet.of("a", "b", "c")或者ImmutableMap.of("a", 1, "b", 2)
  3. 使用Builder类

Guava的immutale集合的简单使用

    @Test
    public void testGuavaImmutable(){

        List<String> list=new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("c");

        ImmutableList<String> imlist=ImmutableList.copyOf(list);
        System.out.println("imlist:"+imlist);

        ImmutableList<String> imOflist=ImmutableList.of("peida","jerry","harry");
        System.out.println("imOflist:"+imOflist);

        ImmutableSortedSet<String> imSortList=ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");
        System.out.println("imSortList:"+imSortList);

        list.add("baby");
        //关键看这里是否imlist也添加新元素了
        System.out.println("list添加新元素之后看imlist:"+imlist);

        ImmutableSet<Color> imColorSet =
                ImmutableSet.<Color>builder()
                        .add(new Color(0, 255, 255))
                        .add(new Color(0, 191, 255))
                        .build();

        System.out.println("imColorSet:"+imColorSet);
    }
------------------------------------------------------------------------------
运行结果:
imlist:[a, b, c]
imOflist:[peida, jerry, harry]
imSortList:[a, b, c, d]
list添加新元素之后看imlist:[a, b, c]
imColorSet:[java.awt.Color[r=0,g=255,b=255], java.awt.Color[r=0,g=191,b=255]]

更智能的copyOf

copyOf方法比你想象的要智能,ImmutableXXX.copyOf会在合适的情况下避免拷贝元素的操作-先忽略具体的细节,但是它的实现一般都是很“智能”的。譬如:

    @Test
    public void testCotyOf(){
        ImmutableSet<String> imSet=ImmutableSet.of("peida","jerry","harry","lisa");
        System.out.println("imSet:"+imSet);

        //set直接转list
        ImmutableList<String> imlist=ImmutableList.copyOf(imSet);
        System.out.println("imlist:"+imlist);

        //list直接转SortedSet
        ImmutableSortedSet<String> imSortSet=ImmutableSortedSet.copyOf(imSet);
        System.out.println("imSortSet:"+imSortSet);

        List<String> list=new ArrayList<String>();
        for(int i=0;i<=10;i++){
            list.add(i+"x");
        }
        System.out.println("list:"+list);

        //截取集合部分元素
        ImmutableList<String> imInfolist=ImmutableList.copyOf(list.subList(2, 8));
        System.out.println("imInfolist:"+imInfolist);
    }
----------------------------------------------------------------------------
运行结果:
imSet:[peida, jerry, harry, lisa]
imlist:[peida, jerry, harry, lisa]
imSortSet:[harry, jerry, lisa, peida]
list:[0x, 1x, 2x, 3x, 4x, 5x, 6x, 7x, 8x, 9x, 10x]
imInfolist:[2x, 3x, 4x, 5x, 6x, 7x]

ImmutableMap使用举例

public class ImmutableExample3 {

    private final static ImmutableList<Integer> list = ImmutableList.of(1, 2, 3);
    private final static ImmutableSet set = ImmutableSet.copyOf(list);
    private final static ImmutableMap<Integer, Integer> map = ImmutableMap.of(1, 2, 3, 4);//map必须成对出现(偶数个)
    private final static ImmutableMap<Integer, Integer> map2 = ImmutableMap.<Integer, Integer>builder().put(1, 2).put(3, 4).put(5, 6).build();

    public static void main(String[] args) {
        System.out.println(map2.get(3));
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!