Java Collections.checkedSet 方法
上次修改时间:2025 年 4 月 20 日
Collections.checkedSet
方法返回指定 set 的动态类型安全视图。 此包装器确保只有指定类型的元素才能添加到 set 中。 它有助于在运行时捕获类型不匹配,而不是让它们在以后导致问题。
当处理遗留代码或需要在可能被不受信任的代码访问的集合中强制执行类型安全时,此方法特别有用。 如果尝试插入错误类型的元素,checked set 将立即抛出 ClassCastException
。
Collections.checkedSet 概述
checkedSet
方法是 java.util.Collections
实用程序类的一部分。 它接受一个 Set 和一个 Class 对象作为参数,并返回一个强制执行类型检查的新 Set。 返回的 set 由原始 set 支持,因此对一个 set 的更改会反映在另一个 set 中。
其主要目的是提供运行时类型安全。 虽然泛型提供编译时类型检查,但它们在运行时被擦除。 checkedSet
添加了运行时检查,以捕获原始类型或未检查的强制转换可能允许添加不正确元素的情况。
基本的 checkedSet 用法
此示例演示了 Collections.checkedSet
的基本用法。 我们创建一个常规的 HashSet,然后使用一个强制执行 String 元素的 checked set 对其进行包装。 该示例展示了有效和无效的操作。
package com.zetcode; import java.util.Collections; import java.util.HashSet; import java.util.Set; public class BasicCheckedSet { public static void main(String[] args) { Set<String> regularSet = new HashSet<>(); Set<String> checkedSet = Collections.checkedSet(regularSet, String.class); // Valid operation - adding a String checkedSet.add("Hello"); checkedSet.add("World"); System.out.println("Checked set: " + checkedSet); // Invalid operation - trying to add non-String try { checkedSet.add(42); // This will throw ClassCastException } catch (ClassCastException e) { System.out.println("Caught exception: " + e.getMessage()); } } }
此代码创建了一个类型安全的 Set 视图,该视图仅接受 String 元素。 第一个添加操作运行良好,但尝试添加 Integer 会抛出 ClassCastException
。 当添加了错误的类型时,异常会立即发生,从而使调试更容易。
输出显示了成功添加 String 并捕获了尝试添加 Integer 时发生的异常。 这演示了 checkedSet
提供的运行时类型检查。
checked Set 与遗留代码
此示例展示了在使用不使用泛型的遗留代码时,checkedSet
如何提供帮助。 我们创建一个原始 Set,然后使用一个 checked set 对其进行包装以强制类型安全。
package com.zetcode; import java.util.Collections; import java.util.HashSet; import java.util.Set; public class LegacyCodeCheckedSet { public static void main(String[] args) { // Legacy code using raw type Set rawSet = new HashSet(); rawSet.add("First"); rawSet.add("Second"); // Wrap with checked set Set<String> checkedSet = Collections.checkedSet(rawSet, String.class); // Valid operation checkedSet.add("Third"); System.out.println("Checked set contents: " + checkedSet); // Attempt to bypass type safety try { rawSet.add(123); // This will throw ClassCastException } catch (ClassCastException e) { System.out.println("Caught exception from raw set: " + e.getMessage()); } } }
此示例演示了即使在使用原始类型时,checkedSet
也能如何强制类型安全。 checked set 监视对底层 set 的所有添加,无论是通过 checked 视图还是直接通过原始 set 引用。
输出显示,尝试通过原始 set 引用添加 Integer 仍然会触发类型检查。 这使得 checkedSet
对于逐步将类型安全引入遗留代码非常有用。
Checked Set 与不同的类型
此示例演示了将 checkedSet
用于不同的元素类型。 我们为不同的类创建 checked set,并展示它们如何强制执行各自的类型约束。
package com.zetcode; import java.util.Collections; import java.util.HashSet; import java.util.Set; public class DifferentTypeCheckedSets { public static void main(String[] args) { // String checked set Set<String> stringSet = Collections.checkedSet(new HashSet<>(), String.class); stringSet.add("Text"); // stringSet.add(123); // Compile-time error // Integer checked set Set<Integer> intSet = Collections.checkedSet(new HashSet<>(), Integer.class); intSet.add(123); // intSet.add("Text"); // Compile-time error // Custom class checked set Set<Person> personSet = Collections.checkedSet(new HashSet<>(), Person.class); personSet.add(new Person("Alice")); System.out.println("String set: " + stringSet); System.out.println("Integer set: " + intSet); System.out.println("Person set: " + personSet); } static class Person { String name; Person(String name) { this.name = name; } @Override public String toString() { return name; } } }
此示例展示了 checkedSet
如何使用不同的类型:字符串、整数和一个自定义的 Person 类。 每个 checked set 都强制执行其特定的类型约束,防止添加不正确的元素。
注释行显示了尝试添加错误类型的情况,这些情况会导致泛型出现编译时错误。 checkedSet
提供的运行时检查为防止类型违规增加了一层额外的保护。
Checked Set 性能考量
此示例探讨了使用 checkedSet
的性能影响。 我们比较了在常规 Set 和 checked Set 上的操作,以了解运行时类型检查的开销。
package com.zetcode; import java.util.Collections; import java.util.HashSet; import java.util.Set; public class CheckedSetPerformance { public static void main(String[] args) { final int ELEMENT_COUNT = 100000; Set<Integer> regularSet = new HashSet<>(); Set<Integer> checkedSet = Collections.checkedSet(new HashSet<>(), Integer.class); // Measure regular set add performance long start = System.nanoTime(); for (int i = 0; i < ELEMENT_COUNT; i++) { regularSet.add(i); } long regularTime = System.nanoTime() - start; // Measure checked set add performance start = System.nanoTime(); for (int i = 0; i < ELEMENT_COUNT; i++) { checkedSet.add(i); } long checkedTime = System.nanoTime() - start; System.out.println("Regular set add time: " + regularTime / 1_000_000 + " ms"); System.out.println("Checked set add time: " + checkedTime / 1_000_000 + " ms"); System.out.println("Overhead: " + (100 * (checkedTime - regularTime) / regularTime) + "%"); } }
此代码测量了将元素添加到常规 Set 和 checked Set 的性能差异。 checkedSet
中的类型检查为每个操作增加了一些开销,此示例对其进行了量化。
输出显示了每个操作所花费的时间,并计算了百分比开销。 虽然存在一定的性能成本,但在关键代码路径中为了增加类型安全性,通常是值得的。
Checked Set 在多线程环境中的应用
此示例演示了 checkedSet
在多线程环境中的行为。 checked set 包装器本身不提供线程安全性,但可以与同步包装器结合使用以实现完全保护。
package com.zetcode; import java.util.Collections; import java.util.HashSet; import java.util.Set; public class ThreadSafeCheckedSet { public static void main(String[] args) throws InterruptedException { Set<String> baseSet = new HashSet<>(); Set<String> safeSet = Collections.synchronizedSet( Collections.checkedSet(baseSet, String.class)); Runnable task = () -> { for (int i = 0; i < 1000; i++) { safeSet.add(Thread.currentThread().getName() + "-" + i); } }; Thread t1 = new Thread(task); Thread t2 = new Thread(task); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println("Set size: " + safeSet.size()); } }
此示例将 checkedSet
与 synchronizedSet
结合使用,以创建一个既类型安全又线程安全的 Set。 多个线程可以安全地将元素添加到 set 中,而不会导致类型违规或数据损坏。
输出显示了两个线程完成后 set 的最终大小。 同步和类型检查的结合为并发访问场景提供了全面的保护。
Checked Set 与 Null 元素
此示例探讨了 checkedSet
如何处理 null 元素。 处理 null 值时,类型检查行为与处理常规元素略有不同。
package com.zetcode; import java.util.Collections; import java.util.HashSet; import java.util.Set; public class CheckedSetWithNulls { public static void main(String[] args) { Set<String> checkedSet = Collections.checkedSet(new HashSet<>(), String.class); // Adding null to a checked set checkedSet.add(null); System.out.println("Set with null: " + checkedSet); // Removing null checkedSet.remove(null); System.out.println("Set after null removal: " + checkedSet); // Checking contains null System.out.println("Contains null? " + checkedSet.contains(null)); // Trying with non-null values checkedSet.add("NotNull"); System.out.println("Set with non-null: " + checkedSet); } }
此示例演示了 checkedSet
允许 null 元素,而不管指定的类型是什么。 类型检查仅应用于非 null 元素,因为 null 没有可供检查的运行时类型。
输出显示,可以添加、删除和检查 null 在 set 中的存在,就像使用常规 Set 一样。 这种行为与 Java 通常处理集合中的 null 的方式一致。
Checked Set 与继承
此最后一个示例检查了 checkedSet
如何使用类继承。 我们使用超类类型创建一个 checked set,并尝试添加超类和子类实例。
package com.zetcode; import java.util.Collections; import java.util.HashSet; import java.util.Set; public class CheckedSetInheritance { public static void main(String[] args) { Set<Number> numberSet = Collections.checkedSet(new HashSet<>(), Number.class); // Adding various Number subclasses numberSet.add(Integer.valueOf(42)); numberSet.add(Double.valueOf(3.14)); numberSet.add(Float.valueOf(1.618f)); System.out.println("Number set: " + numberSet); // Trying to add non-Number try { numberSet.add("Not a number"); } catch (ClassCastException e) { System.out.println("Caught exception: " + e.getMessage()); } } }
此示例显示了 checkedSet
尊重 Java 的继承规则。 使用超类类型(Number)声明的 checked set 可以接受任何子类(Integer、Double、Float)的实例,但拒绝不相关的类型(String)。
输出演示了成功添加各种 Number 子类,并在尝试添加 String 时捕获了异常。 这种行为与 Java 的标准多态规则相符。
来源
Java Collections.checkedSet 文档
在本文中,我们深入探讨了 Java Collections.checkedSet
方法。 我们介绍了基本用法、遗留代码集成、不同类型、性能、线程、空值处理和继承。 了解 checkedSet
对于创建更健壮、类型安全的应用程序很有价值。
作者
列出所有Java教程。