我只是想知道
java.util.Collections.checkedList()
实际用途是什么。
我有一些代码,我知道它会返回一个
List<String>
,但它是通过一系列消息传递调用传递并作为 java.io.Serializable
返回给我的。 checkList 调用是否适合我将我的 Serializable
变成 List<String>
? 我知道我可以将其转换为 java.util.List
,但我不想检查每个元素,而且我不愿意假设每个元素都是 String
。
它部分用作调试工具,用于查找代码插入错误类型的类的位置,以防您看到这种情况发生,但无法弄清楚在哪里。
您可以将其用作提供集合的公共 API 的一部分,并且您希望确保该集合中不会包含错误类型的任何内容(例如,如果客户端删除了泛型)。
您可以在您的案例中使用它的方式是:
Collections.checkedList(
new ArrayList<String>(uncertainList.size()), String.class)
.addAll(uncertainList);
如果没有引发异常,那么您就知道自己做得很好。这并不完全是一段性能优化的代码,但如果列表内容相当小,应该没问题。
不完全是:
Collections.checkedList
只会装饰列表以防止将来插入错误类的对象,它不会检查列表中已有的所有元素。
但是,您可以创建一个新的 checkList,然后调用
addAll
并传入您不确定的列表 - 而不是自己编写循环。
有关
checkedList
用途的讨论可在 checkedCollection 的文档中找到。给出的理由是:
您可以使用 google collections 中的以下内容来检查列表是否仅包含字符串:
Iterables.all(list, Predicates.instanceOf(String.class))
让我们想象一下以下场景:您有一个您知道的类型的列表,例如数字列表。并且您有一个第三方 API,它接受一个列表(不指定类型)。此 API 可能会导致输入列表中出现一些突变(比方说),并且您需要确保第 3 方 API 不会向您的列表中添加其他类型。
一点上下文:(请阅读更多关于擦除的内容)在运行时,泛型变成了对象。
假设您有以下方法:
private static final String STRING_VALUE = "this is actually a string!";
public void addElements(List l) {
l.add(STRING_VALUE);
System.out.println(l);
}
编译时没问题,因为 List 没有指定类型,但你有不安全的代码,这是 Ben 正在讨论的代码示例。
让我们在数字数组列表上测试这个方法:
@Test
public void addingAStringInANumbersList_shouldBeSuccessful() {
List<Number> numbers = new ArrayList<>(List.of(1, 2, 3, 1.0, 2.0f, 3.0f, 5));
addElements(numbers);
Assertions.assertEquals(List.of(1, 2, 3, 1.0, 2.0f, 3.0f, 5, STRING_VALUE), numbers);
}
如果运行上面的代码,就会通过。为什么?因为泛型在运行时被替换为对象,所以列表在运行时是类型安全的,只是在运行时。
让我们尝试检查集合:
@Test
public void addAStringInACheckedList_shouldFail() {
List<Number> numbers = Collections.checkedList(new ArrayList<>(List.of(1, 2, 3, 1.0, 2.0f, 3.0f, 5)), Number.class);
Assertions.assertThrows(ClassCastException.class, () -> addElements(numbers));
}
这将抛出 ClassCastException,这是测试所期望的 => 它将通过。因此,检查的集合可以帮助您处理遗留的第 3 方代码。
PS:Collections 实用程序类仅创建包装器,因此如果您将“核心”集合传递给不安全的第 3 方代码,结果将在检查的集合包装器上可见,例如:
@Test
public void addingAStringInANumbersList_theCheckedListIsJustAWrapper_shouldBeSuccessful() {
List<Number> numbers = new ArrayList<>(List.of(1, 2, 3, 1.0, 2.0f, 3.0f, 5));
List<Number> checkedNumbers = Collections.checkedList(numbers, Number.class);
addElements(numbers);
Assertions.assertEquals(List.of(1, 2, 3, 1.0, 2.0f, 3.0f, 5, STRING_VALUE), numbers);
Assertions.assertEquals(List.of(1, 2, 3, 1.0, 2.0f, 3.0f, 5, STRING_VALUE), checkedNumbers);
}
我希望现在检查收藏的目的已经明确。