851

我需要Set用初始值创建一个。

Set<String> h = new HashSet<String>();
h.add("a");
h.add("b");

有没有办法在一行代码中做到这一点?例如,它对于最终的静态字段很有用。

4

24 回答 24

1081

我使用的速记不是很省时,但适合一行:

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));

稍微不那么丑陋和效率对于静态初始化无关紧要。

于 2010-01-11T12:38:01.390 回答
388

集合文字是为 Java 7 安排的,但没有进入。所以还没有自动的。

您可以使用番石榴的Sets

Sets.newHashSet("a", "b", "c")

或者您可以使用以下语法,这将创建一个匿名类,但它很 hacky:

Set<String> h = new HashSet<String>() {{
    add("a");
    add("b");
}};
于 2010-01-11T12:34:12.393 回答
257

如果您正在寻找最紧凑的初始化集合的方法,那么就是Java9

Set<String> strSet = Set.of("Apple", "Ball", "Cat", "Dog");

=====================下面详细解答==========================

使用 Java 10(不可修改集)

Set<String> strSet1 = Stream.of("A", "B", "C", "D")
         .collect(Collectors.toUnmodifiableSet());

在这里,收集器实际上将返回 Java 9 中引入的不可修改集,这从set -> (Set<T>)Set.of(set.toArray())源代码中的语句可以明显看出。

需要注意的一点是,该方法Collections.unmodifiableSet()返回指定集合的​​不可修改视图(根据文档)。不可修改的视图集合是不可修改的集合,也是支持集合的视图。请注意,对支持集合的更改可能仍然是可能的,并且如果发生更改,它们将通过不可修改的视图可见。但是该方法Collectors.toUnmodifiableSet()返回Java 10中真正不可变的集合。


使用 Java 9(不可修改集)

以下是初始化集合的最简洁方式:

Set<String> strSet6 = Set.of("Apple", "Ball", "Cat", "Dog");

我们有这个便利工厂方法的 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(可修改集)

在 Java 8 中使用流。

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));

使用 Java 8(不可修改集)

使用 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).

还要检查Java 8 的这个答案。

于 2016-05-24T06:36:33.580 回答
221

在 Java 8 中,我会使用:

Set<String> set = Stream.of("a", "b").collect(Collectors.toSet());

这为您提供了一个Set用“a”和“b”预初始化的可变变量。请注意,虽然在 JDK 8 中这确实返回 a HashSet,但规范并不能保证它,而且这可能会在未来发生变化。如果您特别想要 a HashSet,请改为执行以下操作:

Set<String> set = Stream.of("a", "b")
                        .collect(Collectors.toCollection(HashSet::new));
于 2014-01-13T04:49:15.783 回答
91

有几种方法:

双括号初始化

这是一种创建匿名内部类的技术,该内部类具有实例初始化程序,该初始化程序String在创建实例时将 s 添加到自身:

Set<String> s = new HashSet<String>() {{
    add("a");
    add("b");
}}

请记住,这实际上会在HashSet每次使用它时创建一个新的子类,即使您不必显式地编写一个新的子类。

一种实用方法

编写一个返回Set用所需元素初始化的 a 的方法并不难编写:

public static Set<String> newHashSet(String... strings) {
    HashSet<String> set = new HashSet<String>();

    for (String s : strings) {
        set.add(s);
    }
    return set;
}

上面的代码只允许使用 a String,但允许使用任何使用泛型的类型应该不会太难。

使用图书馆

许多库都有一个方便的方法来初始化集合对象。

例如,Google Collections有一个Sets.newHashSet(T...)方法可以HashSet用特定类型的元素填充 a。

于 2010-01-11T12:34:48.013 回答
59

最方便的方法之一是使用泛型Collections.addAll()方法,它接受一个集合和可变参数:

Set<String> h = new HashSet<String>();
Collections.addAll(h, "a", "b");
于 2016-11-22T02:41:52.150 回答
54

如果您只有一个值并且想要获得一个不可变的集合,这就足够了:

Set<String> immutableSet = Collections.singleton("a");
于 2015-10-05T07:51:19.343 回答
35

使用 Java 9,您可以执行以下操作:

Set.of("a", "b");

你会得到一个包含元素的不可变集合。有关详细信息,请参阅接口 Set 的 Oracle 文档

于 2017-07-05T09:30:39.993 回答
29

你可以在 Java 6 中做到这一点:

Set<String> h = new HashSet<String>(Arrays.asList("a", "b", "c"));

但为什么?我不觉得它比显式添加元素更具可读性。

于 2010-01-11T12:36:23.283 回答
29

我觉得最易读的是简单地使用google Guava

Set<String> StringSet = Sets.newHashSet("a", "b", "c");

它是可变的。

于 2014-10-29T18:05:55.940 回答
13

coobird 的答案HashSet用于创建新s的效用函数的概括:

public static <T> Set<T> newHashSet(T... objs) {
    Set<T> set = new HashSet<T>();
    for (T o : objs) {
        set.add(o);
    }
    return set;
}
于 2010-08-29T23:49:55.320 回答
13

如果 Set 的包含类型是枚举,则有 java 内置工厂方法(从 1.5 开始):

Set<MY_ENUM> MY_SET = EnumSet.of( MY_ENUM.value1, MY_ENUM.value2, ... );
于 2015-12-23T07:16:16.043 回答
9
import com.google.common.collect.Sets;
Sets.newHashSet("a", "b");

或者

import com.google.common.collect.ImmutableSet;
ImmutableSet.of("a", "b");
于 2017-07-14T16:29:12.290 回答
6

使用Eclipse Collections有几种不同的方法来初始化Set在一个语句中包含字符 'a' 和 'b' 的 a。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 的提交者。

于 2016-02-29T20:41:19.150 回答
4

只是一个小提示,无论您最终使用哪种方法,如果这是通常未修改的默认设置(例如您正在创建的库中的默认设置),那么遵循此模式是一个好主意:

// Initialize default values with the method you prefer, even in a static block
// It's a good idea to make sure these defaults aren't modifiable
private final static Set<String> DEFAULT_VALUES = Collections.unmodifiableSet(...);
private Set<String> values = DEFAULT_VALUES;

好处取决于您为该类创建的实例数量以及更改默认值的可能性。

如果您决定遵循这种模式,那么您还可以选择最易读的集合初始化方法。由于不同方法之间效率上的微小差异可能并不重要,因为您只需初始化一次集合。

于 2015-11-11T09:21:27.383 回答
4

(丑陋)无副作用的双大括号初始化:

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");
}})
于 2017-08-09T19:31:07.533 回答
4

随着的发布和便利的工厂方法,这可以以一种更简洁的方式实现:

Set set = Set.of("a", "b", "c");
于 2017-09-27T17:55:50.030 回答
3

有点复杂,但适用于 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));
}
于 2010-01-11T12:38:21.283 回答
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));
于 2017-12-08T09:24:50.497 回答
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);
}
于 2017-05-17T06:24:15.380 回答
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);
            }
        };
}
于 2015-05-12T14:37:14.707 回答
0

Builder 模式可能在这里有用。今天我遇到了同样的问题。我需要 Set 变异操作来返回 Set 对象的引用,所以我可以将它传递给超类构造函数,以便它们也可以继续添加到同一个集合中,依次从子类的 Set 中构造一个新的 StringSetBuilder刚刚建成。我编写的构建器类看起来像这样(在我的例子中,它是一个外部类的静态内部类,但它也可以是它自己的独立类):

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()andadd()方法,它们是 Set 返回Set.add()and的对应项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());
    }
}
于 2017-11-03T16:44:17.743 回答
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
  }
  • 如果您为 init 传递一些值,这很好,对于任何大型使用其他方法
  • 如果您不小心将类型与buildSetModif生成的 T will be混合在一起? extends Object,这可能不是您想要的,则buildSetModifTypeSafe变体不会发生这种情况,这意味着 buildSetModifTypeSafe(1, 2, "a");不会编译
于 2019-05-27T08:50:56.320 回答
0

您还可以使用vavr

import io.vavr.collection.HashSet;

HashSet.of("a", "b").toJavaSet();
于 2020-10-20T23:31:55.620 回答