java不可变对象 代码演示

本文中主要以代码及部分源码为示例介绍:final、Collections.unmodifiableXXX、ImmutableXXX 三种不可变对象的使用,主要是演示使用,main中的代码并不是完整符合逻辑,主要为了呈现出错的效果方便理解。

环境:jdk1.8   boot 

jar:

<!--日志-->        
<dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <version>1.16.10</version>
</dependency>
<!--guava-->  
<dependency>
   <groupId>com.google.guava</groupId>
   <artifactId>guava</artifactId>
   <version>23.0</version>
</dependency>

 

一、不可变对象-final

定义:

●修饰类——该不能被继承(参考String的实现)

         注意:使用final修饰类的时候,其所有方法都会被隐式的声明为final(慎重选择将类声明为final类)

●修饰方法——锁定该方法不被继承类修改

        注意:一个类的private方法会被隐式的声明为final方法

●修饰变量——基本数据类型的变量值不能被改变,引用型变量其指向的地址不能被改变

代码示例(可以自行运行测试):

import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;

/**
 * 不可变对象-final
 * @author stx
 * @date 2018/5/16 14:14
 * @desc
 */
@Slf4j
public class ImmutableExample {

    private final static int num = 0;
    private final static String a = "aa";
    private final static Map<Integer, String> map = new HashMap<Integer, String>(){{put(1,"a");put(2,"b");put(3,"b");}};

    public static void main(String[] args) {
        //num = 0; //编辑器直接提示错误
        //a = "b";//编辑器直接提示错误
//        map = new HashMap<Integer, String>();//编辑器直接提示错误

        map.put(2, "bb");
        log.info(map.get(2));
    }
}

       这里只是针对final修饰变量做了示例。

分析下:由示例我们可知被final修饰基本数据类型的变量值不能被改变,引用型变量其指向的地址不能被改变。 值得注意的是final修饰的map在进行初始化后,地址虽然没有发生改变,但是map里面的对象对应的值缺发生了改变;由此我们可以发现被final修饰的引用型变量示例中的做法是不安全的,那我们改怎么办呢?下面我推荐两种解决方案,请接着往下看示例。

二、不可变对象-Collections.unmodifiableXX map、list、set

代码示例(可以自行运行测试):

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;

import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * 不可变对象-Collections.unmodifiableXX  map、list、set
 * @author stx
 * @date 2018/5/16 14:14
 * @desc
 */
@Slf4j
public class ImmutableExample1 {

    private static Map<Integer, String> map = Maps.newHashMap();
    private static List<Integer> list  = Lists.newArrayList();

    static {
        map.put(1,"a");
        map.put(2,"b");
        map.put(3,"c");
        map = Collections.unmodifiableMap(map);

        list.add(1);
        list.add(2);
        list.add(3);
        list = Collections.unmodifiableList(list);
    }

    public static void main(String[] args) {
        log.info(String.valueOf(list.get(2)));

        map.put(2, "bb");
        log.info(map.get(2));
    }
}

先贴下运行结果(list 执行成功,map 执行抛异常:UnsupportedOperationException)

16:19:51.162 [main] INFO com.yan.spring.springboot.example.ImmutableExample1 - 3
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.util.Collections$UnmodifiableMap.put(Collections.java:1457)
	at com.yan.spring.springboot.example.ImmutableExample1.main(ImmutableExample1.java:38)

针对map的异常我们一起分析下,map对象执行这行代码之后

map = Collections.unmodifiableMap(map); 我们跟进unmodifiableMap的源码,发现这里new了一个新的UnmodifiableMap对象

    public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K, ? extends V> m) {
        return new UnmodifiableMap<>(m);
    }

而创建对象的类中除了读取方法基本都替换成如下实现:

throw new UnsupportedOperationException();

所以运行结果时map抛出了不支持操作的异常;那么我们平时使用不可变容器的时候就可以使用以上方式了。

这里没有提供set的示例,set使用:Collections.unmodifiableSet

 

三、不可变对象-ImmutableXX set、list、set

代码示例(可以自行运行测试):

import com.google.common.collect.*;
import lombok.extern.slf4j.Slf4j;

import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * 不可变对象-ImmutableXX  set、list、set
 *
 * @author stx
 * @date 2018/5/16 14:14
 * @desc
 */
@Slf4j
public class ImmutableExample3 {

    //map 初始化
    private static ImmutableMap<Integer, String> map = ImmutableMap.<Integer, String>builder()
            .put(1,"a")
            .put(2,"b")
            .put(3,"c")
            .build();

    //map2 初始化 参数顺序:K,V,K,V
    private static ImmutableMap<Integer, String> map2 = ImmutableMap.of(1,"a",2,"b");

    //list 初始化
    private static ImmutableList<Integer> list = ImmutableList.of(1,2,3);

    //list 初始化  of 方式省略
    private static ImmutableSet set = ImmutableSet.copyOf(list);

    public static void main(String[] args) {
        map.put(2, "bb");//方法过时
        log.info(map.get(2));

        list.add(3);//方法过时
        log.info(String.valueOf(list.get(2)));
    }
}

相信有编程基础的同学看到上面的代码基本上已经会用了,这里运行结果也是抛出异常:UnsupportedOperationException  我就不做过多解释了。

map.put(2, "bb");//方法过时
list.add(3);//方法过时

这两行代码的调用对应的put、add 方法实现也是:

throw new UnsupportedOperationException();

 

总结:不可变对象的使用比较简单,以上只是演示最常用的几个案例,不可变对象上面演示的源码包中还有很多类,有兴趣的可以自己去学习。

转载于:https://my.oschina.net/u/1034447/blog/1813654

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值