如何通过构造来初始化HashSet值?
我需要创建一个带有初始值的Set
。
Set<String> h = new HashSet<String>();
h.add("a");
h.add("b");
有没有办法用一行代码来做到这一点?例如,它对于最终静态字段很有用。
I need to create a Set
with initial values.
Set<String> h = new HashSet<String>();
h.add("a");
h.add("b");
Is there a way to do this in one line of code? For instance, it's useful for a final static field.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(25)
我使用的速记不是很省时,但适合单行:
同样,这不是很省时,因为您正在构造一个数组,转换为一个列表并使用该列表来创建一个集合。
当初始化静态最终集时,我通常这样写:
稍微不那么难看,并且效率对于静态初始化来说并不重要。
There is a shorthand that I use that is not very time efficient, but fits on a single line:
Again, this is not time efficient since you are constructing an array, converting to a list and using that list to create a set.
When initializing static final sets I usually write it like this:
Slightly less ugly and efficiency does not matter for the static initialization.
集合文字原定在 Java 7 中使用,但没有实现。所以还没有什么自动的。
您可以使用 guava 的
Sets
:或者您可以使用以下语法,这将创建一个匿名类,但它很hacky:
Collection literals were scheduled for Java 7, but didn't make it in. So nothing automatic yet.
You can use guava's
Sets
:Or you can use the following syntax, which will create an anonymous class, but it's hacky:
如果您正在寻找初始化集合的最紧凑的方法,那么 Java9 中就是:
===================== 详细答案如下==========================
使用 Java 10(不可修改集)
这里收集器实际上会返回 Java 9 中引入的不可修改集,从语句
set ->源代码中的 (Set)Set.of(set.toArray())
。需要注意的一点是方法
Collections.unmodifyingSet()
返回指定集的不可修改视图(根据文档)。 不可修改的视图集合是不可修改的集合,也是支持集合的视图。请注意,对支持集合的更改可能仍然是可能的,并且如果发生,它们可以通过不可修改的视图可见。但是方法Collectors .toUnmodifyingSet()
返回 Java 10 中的真正不可变集。使用 Java 9(不可修改的集)
以下是初始化集的最紧凑方式:
我们有 12 个重载版本便利工厂方法:
那么一个自然的问题是为什么当我们有 var-args 时我们需要重载版本?答案是:每个 var-arg 方法都会在内部创建一个数组,并且具有重载版本可以避免不必要的对象创建,并且还可以节省我们的垃圾收集开销。
使用 Java 8(可修改集)
使用 Stream。
使用 Java 8(不可修改集)
使用 Collections.unmodifyingSet()
我们可以使用
Collections.unmodifyingSet()
as:但是看起来有点尴尬,我们可以像这样编写自己的收集器:
然后将其用作:
使用 Collectors.collectingAndThen()
另一种方法是使用方法
Collectors.collectingAndThen()
让我们执行额外的整理转换:如果我们只关心
Set
那么我们也可以使用Collectors.toSet()
代替Collectors.toCollection(HashSet::new)
。另请检查 Java 8 的此答案。
If you are looking for the most compact way of initializing a set then that was in
Java9
:===================== Detailed answer below ==========================
Using Java 10 (Unmodifiable Sets)
Here the collector would actually return the unmodifiable set introduced in Java 9 as evident from the statement
set -> (Set<T>)Set.of(set.toArray())
in the source code.One point to note is that the method
Collections.unmodifiableSet()
returns an unmodifiable view of the specified set (as per documentation). An unmodifiable view collection is a collection that is unmodifiable and is also a view onto a backing collection. Note that changes to the backing collection might still be possible, and if they occur, they are visible through the unmodifiable view. But the methodCollectors.toUnmodifiableSet()
returns truly immutable set in Java 10.Using Java 9 (Unmodifiable Sets)
The following is the most compact way of initializing a set:
We have 12 overloaded versions of this convenience factory method:
Then a natural question is why we need overloaded versions when we have var-args? The answer is: every var-arg method creates an array internally and having the overloaded versions would avoid unnecessary creation of object and will also save us from the garbage collection overhead.
Using Java 8 (Modifiable Sets)
Using Stream in Java 8.
Using Java 8 (Unmodifiable Sets)
Using Collections.unmodifiableSet()
We can use
Collections.unmodifiableSet()
as:But it looks slightly awkward and we can write our own collector like this:
And then use it as:
Using Collectors.collectingAndThen()
Another approach is to use the method
Collectors.collectingAndThen()
which lets us perform additional finishing transformations:If we only care about
Set
then we can also useCollectors.toSet()
in place ofCollectors.toCollection(HashSet::new)
.Also check this answer for Java 8.
在 Java 8 中,我会使用:
这为您提供了一个用“a”和“b”预先初始化的可变
Set
。请注意,虽然在 JDK 8 中,这确实返回一个HashSet
,但规范并不保证它,并且将来可能会发生变化。如果您特别想要一个HashSet
,请执行以下操作:In Java 8 I would use:
This gives you a mutable
Set
pre-initialized with "a" and "b". Note that while in JDK 8 this does return aHashSet
, the specification doesn't guarantee it, and this might change in the future. If you specifically want aHashSet
, do this instead:有几种方法:
双括号初始化
这是一种创建匿名内部类的技术,该内部类具有实例初始值设定项,在创建实例时将
String
添加到自身:请记住,这实际上会创建 < 的新子类code>HashSet 每次使用时,即使不必显式编写新的子类。
实用方法
编写返回
Set
编写起来并不难:上面的代码只允许使用
String
,但是允许使用任何使用泛型的类型应该不会太困难。使用库
许多库都有一个方便的方法来初始化集合对象。
例如,Google 收藏集有一个
Sets.newHashSet(T...)
方法将使用特定类型的元素填充HashSet
。There are a few ways:
Double brace initialization
This is a technique which creates an anonymous inner class which has an instance initializer which adds
String
s to itself when an instance is created:Keep in mind that this will actually create an new subclass of
HashSet
each time it is used, even though one does not have to explicitly write a new subclass.A utility method
Writing a method that returns a
Set
which is initialized with the desired elements isn't too hard to write:The above code only allows for a use of a
String
, but it shouldn't be too difficult to allow the use of any type using generics.Use a library
Many libraries have a convenience method to initialize collections objects.
For example, Google Collections has a
Sets.newHashSet(T...)
method which will populate aHashSet
with elements of a specific type.最方便的方法之一是使用通用 Collections.addAll() 方法,它接受一个集合和可变参数:
One of the most convenient ways is usage of generic Collections.addAll() method, which takes a collection and varargs:
如果您只有一个值并且想要获得一个不可变集,这就足够了:
If you have only one value and want to get an immutable set this would be enough:
使用 Java 9,您可以执行以下操作:
您将获得一个包含元素的不可变 Set。详细信息请参见Oracle接口Set的文档 。
With Java 9 you can do the following:
and you'll get an immutable Set containing the elements. For details see the Oracle documentation of interface Set.
您可以在 Java 6 中做到这一点:
但是为什么呢?我认为它比显式添加元素更具可读性。
You can do it in Java 6:
But why? I don't find it to be more readable than explicitly adding elements.
我觉得最具可读性的是简单地使用 google Guava:
它是可变的。
I feel the most readable is to simply use google Guava:
It's mutable.
如果 Set 包含的类型是枚举,则有 java 内置的工厂方法(自 1.5 起):
If the contained type of the Set is an enumeration then there is java built factory method (since 1.5):
coobird 的答案用于创建新
实用程序函数的概括>哈希集
:A generalization of coobird's answer's utility function for creating new
HashSet
s:或者
or
使用 Eclipse Collections 有几种不同的方法来初始化包含以下内容的
Set
一条语句中的字符“a”和“b”。 Eclipse Collections 具有对象和基本类型的容器,因此我说明了如何使用Set
或CharSet
除了可变、不可变、同步和不可修改版本之外两者都有。注意:我是 Eclipse Collections 的提交者。
With Eclipse Collections there are a few different ways to initialize a
Set
containing the characters 'a' and 'b' in one statement. Eclipse Collections has containers for both object and primitive types, so I illustrated how you could use aSet<String>
orCharSet
in addition to mutable, immutable, synchronized and unmodifiable versions of both.Note: I am a committer for Eclipse Collections.
随着 java9 和 便利工厂方法这是可能的以更干净的方式:
With the release of java9 and the convenience factory methods this is possible in a cleaner way:
只是一个小注意事项,无论您最终采用哪种这里提到的好方法,如果这是通常未经修改的默认设置(例如您正在创建的库中的默认设置),那么遵循此模式是一个好主意:
好处取决于您为该类创建的实例数量以及默认值更改的可能性。
如果您决定遵循此模式,那么您还可以选择最具可读性的集初始化方法。由于不同方法之间效率的微小差异可能并不重要,因为您只需初始化该集合一次。
Just a small note, regardless of which of the fine approaches mentioned here you end up with, if this is a default that usually goes unmodified (like a default setting in a library you are creating), it is a good idea to follow this pattern:
The benefit depends on the number of instances you create of that class and how likely it's that defaults will be changed.
If you decide to follow this pattern, then you also get to pick the method of set initialization that's most readable. As the micro differences in efficiency between the different methods will probably not matter much as you will be initializing the set only once.
(丑陋的)双括号初始化没有副作用:
但在某些情况下,如果我们提到这是使最终集合不可变的好味道,它可能非常有用:
(ugly) Double Brace Initialization without side effects:
But in some cases, if we mentioned that is a good smell to make final collections unmutable, it could be really useful:
有点复杂,但从 Java 5 开始工作:
使用辅助方法使其可读:
A bit convoluted but works from Java 5:
Use a helper method to make it readable:
使用Java 8,我们可以将
HashSet
创建为:如果我们想要不可修改的集合,我们可以创建一个实用方法,如下所示:
此方法可以用作:
Using Java 8 we can create
HashSet
as:And if we want unmodifiable set we can create a utility method as :
This method can be used as :
可以使用静态块进行初始化:
Can use static block for initialization:
这是一个优雅的解决方案:
This is an elegant solution:
建造者模式可能在这里有用。今天我遇到了同样的问题。我需要 Set 变异操作来返回 Set 对象的引用,这样我就可以将它传递给超类构造函数,以便它们也可以通过依次从子类的 Set 构造一个新的 StringSetBuilder 来继续添加到同一个集合中刚刚建成。我编写的构建器类如下所示(在我的例子中,它是外部类的静态内部类,但它也可以是它自己的独立类):
注意
addAll()
和add()
方法,它们是返回Set.add()
和Set.addAll()
对应项的 Set。最后请注意build()
方法,该方法返回对构建器封装的 Set 的引用。下面说明了如何使用此集合构建器:The Builder pattern might be of use here. Today I had the same issue. where I needed Set mutating operations to return me a reference of the Set object, so I can pass it to super class constructor so that they too can continue adding to same set by in turn constructing a new StringSetBuilder off of the Set that the child class just built. The builder class I wrote looks like this (in my case it's a static inner class of an outer class, but it can be its own independent class as well):
Notice the
addAll()
andadd()
methods, which are Set returning counterparts ofSet.add()
andSet.addAll()
. Finally notice thebuild()
method, which returns a reference to the Set that the builder encapsulates. Below illustrates then how to use this Set builder:将 Michael Berdyshev 的答案与泛型相结合,并使用带有initialCapacity的构造函数,与
Arrays.asList
变体进行比较:使用其他方法
buildSetModif
混合使用,则生成的 T 将是<代码>? extends Object,这可能不是您想要的,使用
buildSetModifTypeSafe
变体不会发生这种情况,这意味着buildSetModifTypeSafe(1, 2, "a");
不会编译Combining answer by Michael Berdyshev with Generics and using constructor with initialCapacity, comparing with
Arrays.asList
variant:use other methods
buildSetModif
the resulting T willbe
? extends Object
, which is probably not what you want, this cannot happen with thebuildSetModifTypeSafe
variant, meaning thatbuildSetModifTypeSafe(1, 2, "a");
will not compile您还可以使用 vavr:
You can also use vavr:
为了填充增量整数值或简单地用值 x 初始化长度为 n 的集合,我们可以这样做:
(Java 8)
填充从 0 到 9 的所有值(n-1,增量 10 个值):
或者,填充所有值常量值:
或者也使用 Stream,填充现有列表:
最后,将其与匿名构造函数结合使用,例如其中之一
此代码基本上缩短了经典的 for 循环,因此效率不高,但适合一行
For filling with incremental integer values or simply initialize the set of length n with value x we can do:
(Java 8)
to fill all the value from 0 to 9 (n-1, 10 values incrementally):
or, to fill all with a constant value:
or also using Stream, to fill with an existing list:
Finally, combine this with anonymous constructor, e.g. one of these
This code basically shorten the classic for-loop, so not so efficient but fits in one line