Java不可变地图的示例

时间:2020-01-09 10:35:04  来源:igfitidea点击:

在Java 9中,添加了新的静态工厂方法以在Java中创建不可变的Map。在本文中,我们将看到一个使用工厂方法创建不可变Map的示例,以及如何使它比以前使用Collections.unmodifiableMap()的选项更方便。

我们不能从不可变的Map中删除或者添加元素。调用Map上的任何mutator方法总是会引发UnsupportedOperationException。

在Java 9之前创建不可变或者不可修改的Map

在Java 9之前,Collections.unmodifiableMap()方法用于创建不可变的Map。使用此方法要注意的一件事是仍可以修改原始Map。

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class ImmutMap {
  public static void main(String[] args) {
    Map<String, String> numMap = new HashMap<String, String>();
    numMap.put("1", "One");
    numMap.put("2", "Two");
    numMap.put("3", "Three");
    numMap.put("4", "Four");
    Map<String, String> iMap = Collections.unmodifiableMap(numMap);
    // Original map can be changed
    numMap.put("5", "Five");
    System.out.println("numMap" + numMap);
    //Throws exception as this Map is an unmodifiable view
    iMap.put("6", "Six");
  }
}

输出:

numMap{1=One, 2=Two, 3=Three, 4=Four, 5=Five}
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.base/java.util.Collections$UnmodifiableMap.put(Collections.java:1455)
	at com.theitroad.proj.Programs.ImmutMap.main(ImmutMap.java:19)

从输出numMap中可以看到,它是原始地图,仍可以修改(添加了一对新地图),但不可变地图无法修改。

向前创建不可变的地图Java 9

从Java 9开始,以下静态工厂方法提供了一种方便的方法来创建不可修改的映射。

  • Map.of()(在Java 9中添加)
  • Map.ofEntries()(在Java 9中添加)
  • Map.copyOf()(在Java 10中添加)

这些方法创建的Map实例具有以下特征:

  • 这些方法创建了不可修改的地图。键和值不能添加,删除或者更新。调用Map上的任何mutator方法总是会引发UnsupportedOperationException。但是,如果所包含的键或者值本身是可变的,则可能会导致Map行为不一致或者其内容似乎发生更改。
  • 空键和值是不允许的。尝试使用空键或者空值创建它们会导致NullPointerException。
  • 如果所有键和值都是可序列化的,则它们是可序列化的。
  • 他们在创建时拒绝重复的密钥。传递给静态工厂方法的重复键会导致IllegalArgumentException。
  • 映射的迭代顺序不确定,可能会发生变化。

Map.of()方法示例

此方法已重载,可以传递0到10个元素。

of()–返回包含零个映射的不可修改的映射。
of(K k1,V v1)–返回包含单个映射的不可修改的映射。
of(K k1,V v1,K k2,V v2)–返回包含两个映射的不可修改映射。
..
..
(K k1,V v1,K k2,V v2,K k3,V v3,K k4,V v4,K k5,V v5,K k6,V v6,K k7,V v7,K k8,V v8, K k9,V v9)–返回包含九个映射的不可修改的映射。
(K k1,V v1,K k2,V v2,K k3,V v3,K k4,V v4,K k5,V v5,K k6,V v6,K k7,V v7,K k8,V v8, K k9,V v9,K k10,V v10)–返回包含十个映射的不可修改的映射。

public class ImmutMap {
  public static void main(String[] args) {
    Map<String, String> numMap = Map.of("1", "One", 
              "2", "Two",
              "3", "Three",
              "4", "Four");

    System.out.println("numMap" + numMap);
    //Throws exception no change in Immutable Map
    numMap.put("5", "Five");
  }
}

输出:

numMap{3=Three, 4=Four, 1=One, 2=Two}
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:72)
	at java.base/java.util.ImmutableCollections$AbstractImmutableMap.put(ImmutableCollections.java:731)
	at com.theitroad.proj.Programs.ImmutMap.main(ImmutMap.java:15)

Java Map.ofEntries()方法

如果我们有10个以上的键/值对,请使用Map.entry方法创建地图条目,然后将这些对象传递给Map.ofEntries方法。此方法返回一个不可修改的映射,其中包含从给定条目中提取的键和值。

public class ImmutMap {
  public static void main(String[] args) {
    Map<String, String> numMap = Map.ofEntries(entry("1", "One"), 
              entry("2", "Two"),
              entry("3", "Three"),
              entry("4", "Four"));

    System.out.println("numMap" + numMap);
  }
}

输出:

numMap{3=Three, 2=Two, 1=One, 4=Four}

Map.copyOf()方法示例

如果要从给定的Map创建一个不变的Map,则可以使用copyOf()方法。给定的Map不能为null,并且不得包含任何null键或者值。如果随后修改了给定的Map,则返回的Map将不会反映此类修改。

public class ImmutMap {
  public static void main(String[] args) {
    Map<String, String> numMap = new HashMap<String, String>();
    numMap.put("1", "One");
    numMap.put("2", "Two");
    numMap.put("3", "Three");
    numMap.put("4", "Four");

    System.out.println("numMap- " + numMap);
    Map<String, String> iMap = Map.copyOf(numMap);
    System.out.println("iMap- " + iMap);

    numMap.put("5", "Five");
    System.out.println("numMap after modification- " + numMap);
    System.out.println("iMap- " + iMap);
  }
}

输出:

numMap- {1=One, 2=Two, 3=Three, 4=Four}
iMap- {3=Three, 2=Two, 1=One, 4=Four}
numMap after modification- {1=One, 2=Two, 3=Three, 4=Four, 5=Five}
iMap- {3=Three, 2=Two, 1=One, 4=Four}

如我们所见,可以修改为创建不可变地图而复制的原始地图,但是该更改不会反映在不可变地图上。