Java 9集合工厂的用法 [英] Usage of Java 9 collection factories

查看:138
本文介绍了Java 9集合工厂的用法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

List.of()或Collections.emptyList() List.of(...)或Collections.unmodifiableList()我提出了两条以下经验法则(也适用于设置 Map 相应的工厂。)

In the context of the comments and answers given at List.of() or Collections.emptyList() and List.of(...) or Collections.unmodifiableList() I came up with two following rules of thumb (which also apply to Set and Map factories accordingly).


  1. 不要替换所有出现次数

继续使用 Collections.emptyList()为了便于阅读,例如初始化惰性字段成员,如:

Keep using Collections.emptyList() for readability and when e.g. initializing lazy field members like:

class Bean {
  private List<Bean> beans = Collection.emptyList();
  public List<Bean> getBeans() {
    if (beans == Collections.EMPTY_LIST) { beans = new ArrayList<>(); }
    return beans;
  }
}




  1. 使用新工厂作为方法参数构建器

使用新工厂 List.of() List 参数调用可执行文件时,c>和变体为快速和较少类型的版本。以下是我目前的替换模式:

Use new factories List.of() and variants as quick and less-to-type version, when calling an executable with List parameter(s). Here are my current substitution patterns:

Collections.emptyList()       --> List.of()
Collections.singletonList(a)  --> List.of(a)
Arrays.asList(a, ..., z)      --> List.of(a, ..., z)

虚构使用 Collections.indexOfSubList ,以下行

Collections.indexOfSubList(Arrays.asList(1, 2, 3), Collections.emptyList());
Collections.indexOfSubList(Arrays.asList(1, 2, 3), Collections.singletonList(1));
Collections.indexOfSubList(Arrays.asList(1, 2, 3), Arrays.asList(1));
Collections.indexOfSubList(Arrays.asList(1, 2, 3), Arrays.asList(2, 3));
Collections.indexOfSubList(Arrays.asList(1, 2, 3), Arrays.asList(1, 2, 3));

将会读取

Collections.indexOfSubList(List.of(1, 2, 3), List.of());
Collections.indexOfSubList(List.of(1, 2, 3), List.of(1));
Collections.indexOfSubList(List.of(1, 2, 3), List.of(1));
Collections.indexOfSubList(List.of(1, 2, 3), List.of(2, 3));
Collections.indexOfSubList(List.of(1, 2, 3), List.of(1, 2, 3));

你(不同意)吗?

推荐答案

通常,新工厂的使用对于新代码是安全的,其中没有现有代码依赖于现有集合的行为。

Generally, use of the new factories is safe for new code, where there is no existing code that depends on behaviors of the existing collections.

新的集合工厂不是直接替换使用现有API初始化集合的代码的原因有几个。显然,不变性是最突出的原因之一;如果你以后需要修改集合,那显然不可能是不可变的!但是还有其他原因,其中一些非常微妙。

There are several reasons the new collection factories aren't drop-in replacements for code that initializes collections using the existing APIs. Obviously immutability is one of the most prominent reasons; if you need to modify the collection later, it obviously can't be immutable! But there are other reasons as well, some of them quite subtle.

有关使用新API替换现有API的示例,请参阅 JDK-8134373 。评论主题如下: Part1 Part2

For an example of replacement of existing APIs with the new APIs, see JDK-8134373. The review threads are here: Part1 Part2.

以下是问题的概述。

数据包装与复制。有时你有一个数组,例如一个varargs参数,您希望将其作为列表进行处理。有时 Arrays.asList 在这里是最合适的,因为它只是一个包装器。相比之下, List.of 会创建一个副本,这可能是浪费。另一方面,调用者仍然具有包装数组的句柄并且可以修改它,这可能是一个问题,因此有时您需要支付复制它的费用,例如,如果您想保留对它的引用在实例变量中列出。

Array Wrapping vs Copying. Sometimes you have an array, e.g. a varargs parameter, and you want to process it as a list. Sometimes Arrays.asList is the most appropriate thing here, as it's just a wrapper. By contrast, List.of creates a copy, which might be wasteful. On the other hand, the caller still has a handle to the wrapped array and can modify it, which might be a problem, so sometimes you want to pay the expense of copying it, for example, if you want to keep a reference to the list in an instance variable.

散列集合迭代顺序。新的 Set.of Map.of 结构随机化他们的迭代顺序。 HashSet HashMap 的迭代顺序未定义,但实际上它相对稳定。代码可能会对迭代顺序产生无意的依赖。切换到新的集合工厂可能会将旧代码暴露给迭代顺序依赖项,从而出现潜在的错误。

Hashed Collection Iteration Order. The new Set.of and Map.of structures randomize their iteration order. The iteration order of HashSet and HashMap is undefined, but in practice it turns out to be relatively stable. Code can develop inadvertent dependencies on iteration order. Switching to the new collection factories may expose old code to iteration order dependencies, surfacing latent bugs.

禁止空值。新集合禁止空值完全,而常见的非并发集合( ArrayList HashMap )允许它们。

Prohibition of Nulls. The new collections prohibit nulls entirely, whereas the common non-concurrent collections (ArrayList, HashMap) allow them.

序列化格式。新集合具有与旧集合不同的序列化格式。如果集合是序列化的,或者它存储在序列化的其他类中,则序列化输出将有所不同。这可能是也可能不是问题。但是,如果您希望与其他系统进行互操作,则可能会出现问题。特别是,如果将新集合的序列化形式传输到Java 8 JVM,它将无法反序列化,因为Java 8上不存在新类。

Serialization Format. The new collections have a different serialization format from the old ones. If the collection is serialized, or it's stored in some other class that's serialized, the serialized output will differ. This might or might not be an issue. But if you expect to interoperate with other systems, this could be a problem. In particular, if you transmit the serialized form of the new collections to a Java 8 JVM, it will fail to deserialize, because the new classes don't exist on Java 8.

严格的Mutator方法行为。新的集合是不可变的,所以当调用mutator方法时,它们当然会抛出 UnsupportedOperationException 。但是,有一些边缘情况,其中行为在所有集合中不一致。例如,

Strict Mutator Method Behavior. The new collections are immutable, so of course they throw UnsupportedOperationException when mutator methods are called. There are some edge cases, however, where behavior is not consistent across all the collections. For example,

    Collections.singletonList("").addAll(Collections.emptyList())

什么都不做,而

    List.of("").addAll(Collections.emptyList())

将抛出UOE。一般来说,即使没有发生实际的突变,新的集合和不可修改的包装器在任何调用mutator方法时都会严格地抛出UOE。其他不可变集合(例如来自 Collections.empty * Collections.singleton * 的集合)仅在以下情况下才会抛出UOE会发生实际的突变。

will throw UOE. In general, the new collections and the unmodifiable wrappers are consistently strict in throwing UOE on any call to a mutator method, even if no actual mutation would occur. Other immutable collections, such as those from Collections.empty* and Collections.singleton*, will throw UOE only if an actual mutation would occur.

重复。新的设置 Map 工厂拒绝重复的元素和键。如果您使用常量列表初始化集合,这通常不是问题。实际上,如果一个常量列表有重复,那可能就是一个bug。在这可能存在问题的情况下,允许调用者传入元素的集合或数组(例如,varags)。如果调用者传入重复项,则现有API将默默地省略重复项,而新工厂将抛出 IllegalArgumentException 。这是一个可能影响来电者的行为变化。

Duplicates. The new Set and Map factories reject duplicate elements and keys. This is usually not a problem if you're initializing a collection with a list of constants. Indeed, if a list of constants has a duplicate, it's probably a bug. Where this is potentially an issue is when a caller is allowed to pass in a collection or array (e.g., varags) of elements. If the caller passes in duplicates, the existing APIs would silently omit the duplicates, whereas the new factories will throw IllegalArgumentException. This is a behavioral change that might impact callers.

这些问题都不是致命问题,但它们是行为差异,在改造现有代码时应注意。不幸的是,这意味着用新的收集工厂大规模替换现有的调用可能是不明智的。可能需要在每个站点进行一些检查,以评估行为变化的任何潜在影响。

None of these issues are fatal problems, but they are behavioral differences that you should be aware of when retrofitting existing code. Unfortunately this means that doing a mass replacement of existing calls with the new collection factories is probably ill-advised. It's probably necessary to do some inspection at each site to assess any potential impact of the behavioral changes.

这篇关于Java 9集合工厂的用法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆