Java Collections.singletonMap 方法
最后修改时间:2025 年 5 月 1 日
Collections.singletonMap 方法是 Java Collections 框架中一个有用的工具,它允许创建一个包含恰好一个键值对的不可变 Map。作为 java.util.Collections 类的一部分,它提供了一种简化的方法来处理单条目 Map,而无需使用完整的集合。
当需要一个单条目 Map 且不需要修改时,单例 Map 是理想的选择。它们具有很高的内存效率,并且本质上是线程安全的,这使得它们在并发环境中成为一个可靠的选择。自 Java 1.3 引入以来,singletonMap 一直是简化基于 Map 操作的常用工具。
Collections.singletonMap 概述
Collections.singletonMap 方法返回一个不可变且可序列化的 Map,其中包含单个键值对。虽然它实现了 Map 接口,但任何试图修改其内容(例如添加或删除元素)的操作都会导致 UnsupportedOperationException。
singletonMap 的关键特征包括
- 固定大小,恰好有一个条目。
- 支持空值(如果值类型允许)。
- 优化内存使用,不分配额外的存储空间。
- 线程安全设计,使其适用于并发应用程序。
由于其效率和简单性,singletonMap 常用在方法参数、API 调用以及倾向于不可变性而非动态修改的场景中。
基本 singletonMap 用法
此示例演示了 Collections.singletonMap 的最基本用法。我们创建一个包含一个键值对的 Map,并通过尝试修改它来演示其不可变性。
package com.zetcode;
import java.util.Collections;
import java.util.Map;
public class SingletonMapBasic {
public static void main(String[] args) {
// Create singleton map
Map<String, Integer> ageMap = Collections.singletonMap("John", 30);
// Access elements
System.out.println("John's age: " + ageMap.get("John"));
System.out.println("Map size: " + ageMap.size());
try {
// Attempt to modify (will throw exception)
ageMap.put("Alice", 25);
} catch (UnsupportedOperationException e) {
System.out.println("Expected exception: " + e.getMessage());
}
}
}
此代码创建一个单例 Map,其中 "John" 作为键,30 作为值。我们演示了访问值并检查 Map 大小。尝试添加另一个条目会抛出一个异常,证明了其不可变性。
输出显示了成功的读取操作,以及在尝试修改时预期的异常。此行为是单例集合的基础。
在 singletonMap 中使用 Null 值
此示例探讨了 singletonMap 如何处理空值。虽然键不能为 null,但如果值类型允许,值可以为 null。我们演示了这两种情况。
package com.zetcode;
import java.util.Collections;
import java.util.Map;
public class SingletonMapNulls {
public static void main(String[] args) {
// Valid: null value
Map<String, String> validMap =
Collections.singletonMap("config", null);
System.out.println("Config value: " + validMap.get("config"));
try {
// Invalid: null key
Map<String, String> invalidMap =
Collections.singletonMap(null, "value");
} catch (NullPointerException e) {
System.out.println("Expected exception: " + e.getMessage());
}
}
}
示例显示,虽然允许空值(当值类型允许时),但禁止空键。尝试使用空键会抛出 NullPointerException。
此行为与 Java 中的一般 Map 契约相符,其中键不能为 null,但值可以为 null(除非由实现限制)。输出演示了这两种情况。
在方法参数中使用 singletonMap
Collections.singletonMap 方法提供了一种快速的方法,可以将单条目 Map 传递给需要 Map 参数的方法。当调用 API 或实用程序函数(不需要完整的 Map)时,这特别有用。在此示例中,我们模拟一个系统,该系统使用单例 Map 检索特定城市的天气数据。
package com.zetcode;
import java.util.Collections;
import java.util.Map;
public class SingletonMapParameter {
public static void displayWeatherInfo(Map<String, Integer> weatherData) {
System.out.println("Weather Report:");
weatherData.forEach((city, temp) ->
System.out.println("The temperature in " + city + " is " + temp + "°C"));
System.out.println("Total locations processed: " + weatherData.size());
}
public static void main(String[] args) {
// Using singletonMap to pass a single city's weather data
displayWeatherInfo(Collections.singletonMap("Bratislava", 18));
// Alternative approach without singletonMap:
// Map<String, Integer> weatherMap = new HashMap<>();
// weatherMap.put("Bratislava", 18);
// displayWeatherInfo(weatherMap);
}
}
此示例突出显示了 singletonMap 如何简化将单值 Map 传递给方法的操作,从而减少冗余,同时保持效率。无需手动创建和填充可变 Map,单例 Map 提供了一种简化的替代方案。
这种模式被广泛应用于 Java 应用程序中,特别是在 API 调用、配置设置以及只需要一个键值对的场景中。输出演示了方法如何无缝地处理单例 Map。
将 singletonMap 与常规 Map 进行比较
此示例比较了 singletonMap 与常规 HashMap 的内存使用和性能特征。我们演示了内存占用和修改行为的差异。
package com.zetcode;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class SingletonMapComparison {
public static void main(String[] args) {
// Singleton map
Map<String, String> singleton =
Collections.singletonMap("id", "A100");
// Regular HashMap
Map<String, String> hashMap = new HashMap<>();
hashMap.put("id", "A100");
System.out.println("Singleton map class: " + singleton.getClass());
System.out.println("HashMap class: " + hashMap.getClass());
// Memory comparison
System.out.println("\nSingleton map overhead: minimal");
System.out.println("HashMap overhead: includes hash table structure");
// Modification comparison
try {
singleton.put("newKey", "value");
} catch (UnsupportedOperationException e) {
System.out.println("\nCannot modify singleton map");
}
hashMap.put("newKey", "value");
System.out.println("HashMap modified successfully");
}
}
该示例突出了单例 Map 和常规 HashMap 之间的主要区别。单例 Map 的内存开销最小,因为它们不需要哈希表结构。它们是不可变的,而 HashMaps 默认是可变的。
输出显示了不同的行为,并提醒我们根据需求选择合适的 Map 类型。单例 Map 非常适合不可变的单条目情况。
在 Java 中使用 singletonMap 与自定义对象
Collections.singletonMap 方法允许创建一个包含单个键值对的不可变 Map。此示例演示了使用自定义对象作为键和值时的行为,特别是使用 Person 记录。我们将探讨对象引用在单例 Map 中的工作方式。
package com.zetcode;
import java.util.Collections;
import java.util.Map;
record Person(String name) { }
public class SingletonMapCustomObjects {
public static void main(String[] args) {
Person john = new Person("John Doe");
Person jane = new Person("Jane Smith");
Map<Person, Person> marriage =
Collections.singletonMap(john, jane);
System.out.println("Marriage mapping:");
marriage.forEach((k, v) ->
System.out.println(k.name() + " is married to " + v.name()));
// Changing the reference doesn't affect the map
john = new Person("Johnny Doe"); // New object, but map remains unchanged
System.out.println("\nAfter modifying original reference:");
marriage.forEach((k, v) ->
System.out.println(k.name() + " is married to " + v.name()));
}
}
此示例强调了 singletonMap 存储对象引用而不是副本。虽然我们将一个新的 Person 实例分配给 john 变量,但原始映射保持不变,因为不可变集合不会动态更新。
此行为在所有 Java 集合中都是一致的:修改引用不会改变已存储在集合中的对象。
Collections 框架中的 singletonMap
此示例显示了 singletonMap 如何融入更广泛的 Collections 框架。我们将把它与其他集合一起使用,并演示互操作性。
package com.zetcode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class SingletonMapInFramework {
public static void main(String[] args) {
// Create a list of singleton maps
List<Map<String, Integer>> mapList = new ArrayList<>();
mapList.add(Collections.singletonMap("Alice", 25));
mapList.add(Collections.singletonMap("Bob", 30));
mapList.add(Collections.singletonMap("Charlie", 35));
System.out.println("List of singleton maps:");
mapList.forEach(map ->
map.forEach((k, v) -> System.out.println(k + ": " + v)));
// Extract all values
List<Integer> ages = new ArrayList<>();
mapList.forEach(map -> ages.addAll(map.values()));
System.out.println("\nAll ages: " + ages);
}
}
在这里,我们看到单例 Map 如何与其他集合类型一起使用。我们创建了一个单例 Map 的列表,每个 Map 代表一个人的年龄。然后,我们将所有值提取到单独的列表中。
这演示了单例 Map 与 Collections 框架其余部分的互操作性。输出显示了列表中所有 Map 的合并数据。
性能注意事项
此最终示例考察了 singletonMap 与常规 Map 相比的性能优势。我们将测量两者使用的内存和访问时间。
package com.zetcode;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class SingletonMapPerformance {
public static void main(String[] args) {
final int iterations = 10_000_000;
// Test singleton map
long startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
Map<Integer, String> map = Collections.singletonMap(i, "value");
}
long singletonTime = System.nanoTime() - startTime;
// Test HashMap
startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
Map<Integer, String> map = new HashMap<>();
map.put(i, "value");
}
long hashMapTime = System.nanoTime() - startTime;
System.out.println("SingletonMap creation time: " +
(singletonTime / 1_000_000) + " ms");
System.out.println("HashMap creation time: " +
(hashMapTime / 1_000_000) + " ms");
System.out.println("Ratio: " +
((double)hashMapTime / singletonTime));
}
}
性能测试表明,当您只需要一个条目时,singletonMap 的创建速度比 HashMap 快得多。它也使用更少的内存,因为它不分配哈希表。
输出演示了创建数百万个 Map 类型的时差。对于不可变性可接受的单条目情况,单例 Map 是最佳选择。
来源
Java Collections.singletonMap 文档
在本文中,我们深入探讨了 Java Collections.singletonMap 方法。我们涵盖了基本用法、空值处理、实际应用、性能以及与其他集合的集成。
作者
列出所有Java教程。