我需要创建一个带有初始值的Set
。
Set<String> h = new HashSet<String>();
h.add("a");
h.add("b");
有没有办法在一行代码中执行此操作?例如,它对最终的静态字段很有用。
答案 0 :(得分:826)
我使用的速记不是非常节省时间,但只适用于一行:
Set<String> h = new HashSet<>(Arrays.asList("a", "b"));
同样,这不是时间效率,因为您正在构建一个数组,转换为一个列表并使用该列表来创建一个集。
初始化静态最终集时,我通常会这样写:
public static final String[] SET_VALUES = new String[] { "a", "b" };
public static final Set<String> MY_SET = new HashSet<>(Arrays.asList(SET_VALUES));
稍微不那么丑陋,效率与静态初始化无关。
答案 1 :(得分:325)
收集文字是为Java 7安排的,但没有进入。所以没有自动化。
您可以使用番石榴Sets
:
Sets.newHashSet("a", "b", "c")
或者您可以使用以下语法,这将创建一个匿名类,但它很hacky:
Set<String> h = new HashSet<String>() {{
add("a");
add("b");
}};
答案 2 :(得分:175)
在Java 8中我会使用:
Set<String> set = Stream.of("a", "b").collect(Collectors.toSet());
这为您提供了一个预先初始化为“a”和“b”的可变Set
。请注意,虽然在JDK 8中这确实返回HashSet
,但规范并不保证,并且这可能在将来发生变化。如果您特别想要HashSet
,请改为:
Set<String> set = Stream.of("a", "b")
.collect(Collectors.toCollection(HashSet::new));
答案 3 :(得分:120)
Set<String> strSet1 = Stream.of("A", "B", "C", "D")
.collect(Collectors.toUnmodifiableSet());
这里的收集器实际上会返回Java 9中引入的不可修改的集合,这从源代码中的语句set -> (Set<T>)Set.of(set.toArray())
可以看出。
Set<String> strSet6 = Set.of("Apple", "Ball", "Cat", "Dog");
我们有这个convenience factory方法的12个重载版本:
static <E> Set<E> of()
static <E> Set<E> of(E e1)
static <E> Set<E> of(E e1, E e2)
// ....等等
static <E> Set<E> of(E... elems)
然后一个自然的问题是为什么在我们有var-args 时我们需要重载版本?答案是:每个var-arg方法在内部创建一个数组,并且重载版本可以避免不必要的对象创建,并且还可以避免垃圾收集开销。
在Java 8中使用Stream。
Set<String> strSet1 = Stream.of("A", "B", "C", "D")
.collect(Collectors.toCollection(HashSet::new));
// stream from an array (String[] stringArray)
Set<String> strSet2 = Arrays.stream(stringArray)
.collect(Collectors.toCollection(HashSet::new));
// stream from a list (List<String> stringList)
Set<String> strSet3 = stringList.stream()
.collect(Collectors.toCollection(HashSet::new));
使用Collections.unmodifiableSet - 我们可以将Collections.unmodifiableSet
用作:
Set<String> strSet4 = Collections.unmodifiableSet(strSet1);
但它看起来有点尴尬,我们可以像这样编写我们自己的收藏家:
class ImmutableCollector {
public static <T> Collector<T, Set<T>, Set<T>> toImmutableSet() {
return Collector.of(HashSet::new, Set::add, (l, r) -> {
l.addAll(r);
return l;
}, Collections::unmodifiablSet);
}
}
然后将其用作:
Set<String> strSet4 = Stream.of("A", "B", "C", "D")
.collect(ImmutableCollector.toImmutableSet());
使用Collectors.collectingAndThen - 另一种方法是使用方法Collectors.collectingAndThen
,它允许我们执行其他完成转换:
import static java.util.stream.Collectors.*;
Set<String> strSet5 = Stream.of("A", "B", "C", "D").collect(collectingAndThen(
toCollection(HashSet::new),Collections::unmodifiableSet));
如果我们只关心Set
,那么我们也可以使用Collectors.toSet()
代替Collectors.toCollection(HashSet::new)
。
需要注意的一点是方法Collections::unmodifiableSet
按照doc返回指定集的不可修改视图。不可修改的视图集合是一个不可修改的集合,也是一个支持集合的视图。请注意,可能仍然可以对支持集合进行更改,如果它们发生,则通过不可修改的视图可以看到它们。但方法Collectors.unmodifiableSet
在 Java 10 中返回真正不可变的集合。
答案 4 :(得分:83)
有几种方法:
双支撑初始化
这是一种创建匿名内部类的技术,该内部类具有实例初始化程序,在创建实例时将String
添加到自身:
Set<String> s = new HashSet<String>() {{
add("a");
add("b");
}}
请记住,每次使用它时,这实际上会创建一个新的HashSet
子类,即使不必显式编写新的子类。
实用程序方法
编写一个返回Set
的方法,该方法用所需的元素初始化并不难写:
public static Set<String> newHashSet(String... strings) {
HashSet<String> set = new HashSet<String>();
for (String s : strings) {
set.add(s);
}
return set;
}
上面的代码只允许使用String
,但允许使用泛型的任何类型都不应该太难。
使用图书馆
许多库都有一种方便的方法来初始化集合对象。
例如,Google Collections有Sets.newHashSet(T...)
方法,该方法会使用特定类型的元素填充HashSet
。
答案 5 :(得分:33)
如果你只有一个初始值,那就足够了:
Set<String> h = Collections.singleton("a");
答案 6 :(得分:27)
你可以在Java 6中实现它:
Set<String> h = new HashSet<String>(Arrays.asList("a", "b", "c"));
但为什么呢?我没有发现它比明确添加元素更具可读性。
答案 7 :(得分:26)
最方便的方法之一是使用通用Collections.addAll()方法,该方法采用集合和变量:
Set<String> h = new HashSet<String>();
Collections.addAll(h, "a", "b");
答案 8 :(得分:24)
我觉得最简单的就是使用google Guava:
Set<String> StringSet = Sets.newSet("a", "b", "c");
答案 9 :(得分:22)
答案 10 :(得分:14)
用于创建新HashSet
的{{3}}效用函数的概括:
public static <T> Set<T> newHashSet(T... objs) {
Set<T> set = new HashSet<T>();
for (T o : objs) {
set.add(o);
}
return set;
}
答案 11 :(得分:11)
如果Set的包含类型是枚举,则有java构建的工厂方法(从1.5开始):
Set<MY_ENUM> MY_SET = EnumSet.of( MY_ENUM.value1, MY_ENUM.value2, ... );
答案 12 :(得分:5)
使用Eclipse Collections,有几种不同的方法可以初始化包含字符的Set
&#39; a&#39}。和&#39; b&#39;在一个声明中。 Eclipse Collections具有对象和基本类型的容器,因此我说明了如何使用Set<String>
或CharSet
以及两者的可变,不可变,同步和不可修改的版本。
Set<String> set =
Sets.mutable.with("a", "b");
HashSet<String> hashSet =
Sets.mutable.with("a", "b").asLazy().into(new HashSet<String>());
Set<String> synchronizedSet =
Sets.mutable.with("a", "b").asSynchronized();
Set<String> unmodifiableSet =
Sets.mutable.with("a", "b").asUnmodifiable();
MutableSet<String> mutableSet =
Sets.mutable.with("a", "b");
MutableSet<String> synchronizedMutableSet =
Sets.mutable.with("a", "b").asSynchronized();
MutableSet<String> unmodifiableMutableSet =
Sets.mutable.with("a", "b").asUnmodifiable();
ImmutableSet<String> immutableSet =
Sets.immutable.with("a", "b");
ImmutableSet<String> immutableSet2 =
Sets.mutable.with("a", "b").toImmutable();
CharSet charSet =
CharSets.mutable.with('a', 'b');
CharSet synchronizedCharSet =
CharSets.mutable.with('a', 'b').asSynchronized();
CharSet unmodifiableCharSet =
CharSets.mutable.with('a', 'b').asUnmodifiable();
MutableCharSet mutableCharSet =
CharSets.mutable.with('a', 'b');
ImmutableCharSet immutableCharSet =
CharSets.immutable.with('a', 'b');
ImmutableCharSet immutableCharSet2 =
CharSets.mutable.with('a', 'b').toImmutable();
Eclipse Collections与Java 5 - 8兼容。
注意:我是Eclipse Collections的提交者。
答案 13 :(得分:5)
import com.google.common.collect.Sets;
Sets.newHashSet("a", "b");
或
import com.google.common.collect.ImmutableSet;
ImmutableSet.of("a", "b");
答案 14 :(得分:4)
有点令人费解,但是从Java 5开始:
Set<String> h = new HashSet<String>(Arrays.asList(new String[] {
"a", "b"
}))
使用辅助方法使其可读:
Set<String> h = asSet ("a", "b");
public Set<String> asSet(String... values) {
return new HashSet<String>(java.util.Arrays.asList(values));
}
答案 15 :(得分:4)
(丑陋)Double Brace Initialization没有副作用:
Set<String> a = new HashSet<>(new HashSet<String>() {{
add("1");
add("2");
}})
但是在某些情况下,如果我们提到这是一个很好的气味,使最终集合不可变,它可能真的很有用:
final Set<String> a = Collections.unmodifiableSet(new HashSet<String>(){{
add("1");
add("2");
}})
答案 16 :(得分:3)
只是一个小小的注释,无论你最终提到哪种优秀方法,如果这是一个通常未经修改的默认设置(如你正在创建的库中的默认设置),这是一个好主意遵循这种模式:
Range("A" & i)
好处取决于您为该类创建的实例数量以及更改默认值的可能性。
如果您决定遵循此模式,那么您还可以选择最易读的设置初始化方法。由于不同方法之间效率的微观差异可能并不重要,因为您只需要初始化一次。
答案 17 :(得分:3)
使用 Java 8 ,我们可以创建HashSet
:
Stream.of("A", "B", "C", "D").collect(Collectors.toCollection(HashSet::new));
如果我们想要不可修改的集合,我们可以创建一个实用程序方法:
public static <T, A extends Set<T>> Collector<T, A, Set<T>> toImmutableSet(Supplier<A> supplier) {
return Collector.of(
supplier,
Set::add, (left, right) -> {
left.addAll(right);
return left;
}, Collections::unmodifiableSet);
}
此方法可用作:
Stream.of("A", "B", "C", "D").collect(toImmutableSet(HashSet::new));
答案 18 :(得分:2)
随着java9和convenience factory methods的发布,这可能会更加清晰:
Set set = Set.of("a", "b", "c");
答案 19 :(得分:1)
可以使用静态块进行初始化:
private static Set<Integer> codes1=
new HashSet<Integer>(Arrays.asList(1, 2, 3, 4));
private static Set<Integer> codes2 =
new HashSet<Integer>(Arrays.asList(5, 6, 7, 8));
private static Set<Integer> h = new HashSet<Integer>();
static{
h.add(codes1);
h.add(codes2);
}
答案 20 :(得分:0)
这是一个优雅的解决方案:
public static final <T> Set<T> makeSet(@SuppressWarnings("unchecked") T... o) {
return new HashSet<T>() {
private static final long serialVersionUID = -3634958843858172518L;
{
for (T x : o)
add(x);
}
};
}
答案 21 :(得分:0)
Builder模式可能在这里有用。今天我遇到了同样的问题。我需要设置变异操作以返回我对Set对象的引用,所以我可以将它传递给超类构造函数,这样它们也可以继续添加到同一个set,从而依次构造一个新的StringSetBuilder,即子类的Set刚刚建成。我写的构建器类看起来像这样(在我的例子中,它是外部类的静态内部类,但它也可以是它自己的独立类):
public interface Builder<T> {
T build();
}
static class StringSetBuilder implements Builder<Set<String>> {
private final Set<String> set = new HashSet<>();
StringSetBuilder add(String pStr) {
set.add(pStr);
return this;
}
StringSetBuilder addAll(Set<String> pSet) {
set.addAll(pSet);
return this;
}
@Override
public Set<String> build() {
return set;
}
}
请注意addAll()
和add()
方法,这些方法设置为返回Set.add()
和Set.addAll()
的对应方。最后注意build()
方法,该方法返回对构建器封装的Set的引用。下面说明如何使用此Set builder:
class SomeChildClass extends ParentClass {
public SomeChildClass(String pStr) {
super(new StringSetBuilder().add(pStr).build());
}
}
class ParentClass {
public ParentClass(Set<String> pSet) {
super(new StringSetBuilder().addAll(pSet).add("my own str").build());
}
}
答案 22 :(得分:0)
将 Michael Berdyshev 的答案与泛型相结合,并使用具有initialCapacity的构造函数,并与Arrays.asList
变体进行比较:
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@SafeVarargs
public static <T> Set<T> buildSetModif(final T... values) {
final Set<T> modifiableSet = new HashSet<T>(values.length);
Collections.addAll(modifiableSet, values);
return modifiableSet;
}
@SafeVarargs
public static <T> Set<T> buildSetModifTypeSafe(final T... values) {
return new HashSet<T>(Arrays.asList(values));
}
@SafeVarargs
public static <T> Set<T> buildeSetUnmodif(final T... values) {
return Collections.unmodifiableSet(buildSetModifTypeSafe(values));
// Or use Set.of("a", "b", "c") if you use Java 9
}
buildSetModif
混合使用,则结果T将
是? extends Object
,可能不是您想要的,而buildSetModifTypeSafe
变体就不会发生,这意味着buildSetModifTypeSafe(1, 2, "a");
无法编译答案 23 :(得分:0)
您也可以使用vavr:
import io.vavr.collection.HashSet;
HashSet.of("a", "b").toJavaSet();