Ben*_*min 17 java collections set java-9
在Java 9中,在Set接口上引入了新的静态工厂方法,称为of(),它接受多个元素,甚至是一个元素数组.
我想将一个列表转换为一个集合,以删除集合中的任何重复条目,这可以通过以下方式完成(在Java 9之前):
Set<String> set = new HashSet<>();
set.addAll(list);
Run Code Online (Sandbox Code Playgroud)
但是我认为使用这个新的Java 9静态工厂方法会很酷:
Set.of(list.toArray())
Run Code Online (Sandbox Code Playgroud)
其中list是先前定义的字符串列表.
但是,唉,java扔了一个IllegalArgumentException元素重复的时候,也在方法的Javadoc中说明了.为什么是这样?
编辑:这个问题不是关于概念上等效主题的另一个问题的重复,Map.of()方法,但明显不同.并非所有()方法的静态工厂都表现相同.换句话说,当我问一些关于Set.of()方法的东西时,我不会点击处理Map.of()方法的问题.
Kay*_*man 25
Set.of()是一种手动创建小的简短方法Set.在这种情况下,如果你给它重复值,那将是一个明显的编程错误,因为你应该自己写出这些元素.即Set.of("foo", "bar", "baz", "foo");显然程序员的错误.
你很酷的方式实际上是一个非常糟糕的方式.如果要将a转换List为a Set,则可以使用Set<Foo> foo = new HashSet<>(myList);或以任何其他方式(例如使用流和收集toSet())来执行此操作.优点包括不做无用toArray(),自己的选择Set(你可能想要LinkedHashSet保留订单)等.缺点包括必须输入更多的代码字符.
在背后的原始设计理念Set.of(),List.of()和Map.of()方法(和它们的许多重载)这里要解释什么是重载的便利工厂方法的集合中的Java 9点和在这里,在这里它提到,重点是小集合,这是一件很在内部API周围都很常见,因此可以获得性能优势.虽然目前这些方法委托varargs方法没有提供任何性能优势,但这很容易改变(虽然不确定阻止是什么).
Era*_*ran 18
该Set.of()工厂方法产生不可变的SetS表示一个给定的元素的个数.
在支持的参数固定数量的变种(static <E> Set<E> of?(),static <E> Set<E> of?(E e1),static <E> Set<E> of?(E e1,E e2),等...),不必重复是容易理解的需求-当你调用这个方法Set.of(a,b,c),你说明你希望创建一个不变Set的正是 3个要素,因此,如果参数包含重复项,则拒绝输入而不是生成较小的输入是有意义的Set.
虽然Set<E> of?(E... elements)变体是不同的(如果允许创建Set任意数量的元素),它遵循其他变体的相同逻辑.如果将n元素传递给该方法,则表明您希望创建一个完全不可变Set的元素,因此不允许重复. n
您还可以创建一个Set从List使用一个班轮(有可能重复):
Set<String> set = new HashSet<>(list);
Run Code Online (Sandbox Code Playgroud)
这在Java 9之前就已经可用了.
你希望这是一个"最后的胜利",就像HashSet我猜的那样,但这是一个刻意的决定(正如斯图尔特马克斯 - 这些解释的创造者).他甚至有一个这样的例子:
Map.ofEntries(
"!", "Eclamation"
.... // lots of other entries
""
"|", "VERTICAL_BAR"
);
Run Code Online (Sandbox Code Playgroud)
选择是因为这可能容易出错,所以应该禁止它.
还要注意Set.of()返回一个不可变的Set,所以你可以将你包装Set成:
Collections.unmodifiableCollection(new HashSet<>(list))
Run Code Online (Sandbox Code Playgroud)
的主要设计目标List.of,Set.of,Map.of,和Map.ofEntries静态工厂方法是让程序员在源代码中明确列出的元素创建这些集合。自然会偏向少数元素或条目,因为它们更常见,但这里的相关特征是元素在源代码中列出。
应该的行为是什么,如果重复的元素提供给Set.of或提供给重复键Map.of或Map.ofEntries?假设元素在源代码中明确列出,这很可能是编程错误。诸如首胜或末胜之类的替代方案似乎很可能会默默地掩盖错误,因此我们决定将重复项视为错误是最好的做法。如果元素被显式列出,如果这是一个编译时错误,那就太好了。但是,直到运行时才会检测到重复项*,因此在那个时候抛出异常是我们能做的最好的事情。
* 将来,如果所有参数都是常量表达式或常量折叠,则 Set 或 Map 创建也可以在编译时进行评估,也可以常量折叠。这可能会在编译时检测到重复项。
如果您拥有一组元素并且想要对它们进行重复数据删除,那么用例又如何呢?这是一个不同的用例,它没有被Set.of和很好地处理Map.ofEntries。得先创建一个中间数组,比较麻烦:
Set<String> set = Set.of(list.toArray());
Run Code Online (Sandbox Code Playgroud)
这不会编译,因为list.toArray()返回一个Object[]. 这将产生Set<Object>无法分配给Set<String>. 你想toArray给你一个String[]:
Set<String> set = Set.of(list.toArray(new String[0]));
Run Code Online (Sandbox Code Playgroud)
这种类型检查,但它仍然会抛出重复异常!提出了另一种选择:
Set<String> set = new HashSet<>(list);
Run Code Online (Sandbox Code Playgroud)
这HashSet是可行的,但您会返回 a ,它是可变的,并且比从 返回的集合占用更多的空间Set.of。您可以通过 a 对元素进行重复数据删除HashSet,从中获取一个数组,然后将其传递给Set.of. 那会奏效,但很糟糕。
幸运的是,这在 Java 10 中已修复。您现在可以编写:
Set<String> set = Set.copyOf(list);
Run Code Online (Sandbox Code Playgroud)
这将从源集合的元素创建一个不可修改的集合,并且重复项不会引发异常。相反,使用任意一个副本。有类似的方法List.copyOf和Map.copyOf。作为奖励,如果源集合已经是正确类型的不可修改集合,则这些方法会跳过创建副本。