# 创建不可变集合

不可变集合就是一旦被创建后 长度不能修改 内容也不能修改的集合

# 不可变集合的应该场景

  • 如果某个数据不能被修改,把它防御性的拷贝到不可变集合中是个很好的实践。

  • 当集合对象被不可信的库调用时,不可变形式是安全的。

    • 简单理解:不想让别人修改集合中的内容

# 创建不可变集合的书写格式

# 不可变集合分类

  • List
  • Set
  • Map

在 List,Set,Map 接口中,都存在静态的 of 方法,可以获取一个不可变的集合。

方法名称说明
static <E> List<E> of(E...elements)创建一个具有指定元素的 List 集合对象
static <E> Set<E> of(E...elements)创建一个具有指定元素的 Set 集合对象
static <K,V> Map<K,V> of(E...elements)创建一个具有指定元素的 Map 集合对象

注意:这个集合不能添加删除修改

# 演示 - List 不可变集合的创建和查询

public static void main(String[] args) {
   // 创建不可变集合 内容为:"张三", "李四", "王五"
   // 这个集合一旦创建后就不能添加,修改,删除了只能进行查询操作
   List<String> lists = List.of("张三", "李四", "王五");
   System.out.println("-------------get获取------------");
   System.out.println(lists.get(0));
   System.out.println(lists.get(1));
   System.out.println(lists.get(2));
   System.out.println("----------增强for----------");
   for (String list : lists) {
      System.out.println(list);
   }
   System.out.println("----------iterator----------");
   Iterator<String> iterator = lists.iterator();
   while(iterator.hasNext()) {
      System.out.println(iterator.next());
   }
}

打印结果:

-------------get获取------------
张三
李四
王五
----------增强for----------
张三
李四
王五
----------iterator----------
张三
李四
王五

# 我们试下删除指定索引元素

public static void main(String[] args) {
   // 创建不可变集合 内容为:"张三", "李四", "王五"
   // 这个集合一旦创建后就不能添加,修改,删除了只能进行查询操作
   List<String> lists = List.of("张三", "李四", "王五");
   // 想要删除指定索引 1 的 不可变集合中的元素
   lists.remove(1);
}

打印结果:

Exception in thread "main" java.lang.UnsupportedOperationException
	at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:142)
	at java.base/java.util.ImmutableCollections$AbstractImmutableList.remove(ImmutableCollections.java:260)
	at jihe.Demo01.main(Demo01.java:11)

报错了。

# 我们试下添加元素

public static void main(String[] args) {
   // 创建不可变集合 内容为:"张三", "李四", "王五"
   // 这个集合一旦创建后就不能添加,修改,删除了只能进行查询操作
   List<String> lists = List.of("张三", "李四", "王五");
   // 想要向不可变集合中添加一个元素:"新成员"
   lists.add("新成员");
}

打印结果:

Exception in thread "main" java.lang.UnsupportedOperationException
	at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:142)
	at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.add(ImmutableCollections.java:147)
	at jihe.Demo01.main(Demo01.java:11)

# 我们试下修改元素

public static void main(String[] args) {
   // 创建不可变集合 内容为:"张三", "李四", "王五"
   // 这个集合一旦创建后就不能添加,修改,删除了只能进行查询操作
   List<String> lists = List.of("张三", "李四", "王五");
   lists.set(1, "新成员");
}

打印结果:

Exception in thread "main" java.lang.UnsupportedOperationException
	at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:142)
	at java.base/java.util.ImmutableCollections$AbstractImmutableList.set(ImmutableCollections.java:262)
	at jihe.Demo01.main(Demo01.java:11)

# 演示 - Set 不可变集合的创建

细节:创建时需要保证 of 中的元素唯一性不可重复否则报错。

public static void main(String[] args) {
   Set<String> sets = Set.of("张三", "李四", "李四", "王五");
}

打印结果:

Exception in thread "main" java.lang.IllegalArgumentException: duplicate element: 李四
	at java.base/java.util.ImmutableCollections$SetN.<init>(ImmutableCollections.java:925)
	at java.base/java.util.Set.of(Set.java:524)
	at jihe.Demo02.main(Demo02.java:7)

它说 "李四" 这个元素重复了

目前报错只能测试 添加,删除。不能测试修改因为 Set 集合不支持直接修改元素,而可以先删除旧元素在进行添加达到修改的目的

public static void main(String[] args) {
   Set<String> sets = Set.of("张三", "李四", "王五");
   // 想要向不可变集合中添加一个元素
   sets.add("新成员");
   // sets.remove(1);
}

打印结果:

Exception in thread "main" java.lang.UnsupportedOperationException
	at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:142)
	at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.add(ImmutableCollections.java:147)
	at jihe.Demo02.main(Demo02.java:9)

# 演示 - Map 不可变集合的创建

public static void main(String[] args) {
   /**
         * 细节 1:键不能重复
         * 细节 2:Map 里面的 of 方法,参数是有上限的,最多只能传递 20 个参数,10 个键值对
         * 细节 3:如果我们要传递多个键值对对象,数量大于 10 个,在 Map 接口中还有一个方法
         */
   Map<String, String> maps = Map.of("o", "张三", "o1", "李四", "o2", "王五");
   System.out.println("-------------------");
   Set<String> sets = maps.keySet();
   for (String key : sets) {
      System.out.println(key + " = " + maps.get(key));
   }
   System.out.println("-------------------");
   Set<Map.Entry<String, String>> entrySet = maps.entrySet();
   for (Map.Entry<String, String> n : entrySet) {
      String key = n.getKey();
      String value = n.getValue();
      System.out.println(key + " = " + value);
   }
}

打印结果:

-------------------
o1 = 李四
o = 张三
o2 = 王五
-------------------
o1 = 李四
o = 张三
o2 = 王五

同样不能进行添加和修改与删除否则报错

# Map 转键值对数组或不可变集合

public static void main(String[] args) {
   /*
            创建 Map 的不可变集合,键值对的数量超过 10 个
        */
   //1. 创建一个普通的 Map 集合
   HashMap<String, String> hm = new HashMap<>();
   hm.put("张三", "南京");
   hm.put("李四", "北京");
   hm.put("王五", "上海");
   hm.put("赵六", "北京");
   hm.put("孙七", "深圳");
   hm.put("周八", "杭州");
   hm.put("吴九", "宁波");
   hm.put("郑十", "苏州");
   hm.put("刘一", "无锡");
   hm.put("陈二", "嘉兴");
   hm.put("aaa", "111");
   //2. 利用上面的数据来获取一个不可变的集合
   // 获取到所有的键值对对象(Entry 对象)
   Set<Map.Entry<String, String>> entries = hm.entrySet();
   // 把 entries 变成一个数组
   // 创建一个空数组
   Map.Entry[] arr1 = new Map.Entry[0];
   //toArray:将 entries 中的键值对拷贝到 arr1 数组中
   //toArray 方法在底层会比较集合的长度跟数组的长度两者的大小
   // 如果集合的长度 > 数组的长度 :数据在数组中放不下,此时会根据实际数据的个数,重新创建数组
   // 如果集合的长度 <= 数组的长度:数据在数组中放的下,此时不会创建新的数组,而是直接用
   Map.Entry[] arr2 = entries.toArray(arr1);
   // 不可变的 map 集合
   Map map = Map.ofEntries(arr2);
   // map.put("bbb","222");
   //Map<Object, Object> map = Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0]));
   //        Map<String, String> map = Map.copyOf(hm);
   //        map.put("bbb", "222");
}