如何通过构造初始化HashSet值?

Ser*_*erg 684 java collections constructor initialization hashset

我需要创建一个Set初始值.

Set<String> h = new HashSet<String>();
h.add("a");
h.add("b");
Run Code Online (Sandbox Code Playgroud)

有没有办法在一行代码中执行此操作?例如,它对最终的静态字段很有用.

Gen*_*diy 883

我使用的速记不是非常节省时间,但适用于单行:

Set<String> h = new HashSet<>(Arrays.asList("a", "b"));
Run Code Online (Sandbox Code Playgroud)

同样,这不是时间效率,因为您正在构建一个数组,转换为一个列表并使用该列表来创建一个集合.

初始化静态最终集时,我通常会这样写:

public static final String[] SET_VALUES = new String[] { "a", "b" };
public static final Set<String> MY_SET = new HashSet<>(Arrays.asList(SET_VALUES));
Run Code Online (Sandbox Code Playgroud)

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

  • 在Java 9中:`Set <String> h = Set.of("a","b")// Unmodifiable` [这个答案是最新的](/sf/answers/2618423811/) (10认同)
  • @Gennadiy可以确认钻石符号工作正常(甚至跨Set声明和HashSet赋值.) (3认同)
  • 尽管在撰写本文时大多数情况下都是正确的,但是从Java 7开始,请使用Diamond运算符,如下所示:Set <String> h = new HashSet <>(Arrays.asList("a","b")); public static final Set <String> MY_SET = new HashSet <>(Arrays.asList(SET_VALUES)); (2认同)

Boz*_*zho 348

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

你可以使用番石榴Sets:

Sets.newHashSet("a", "b", "c")
Run Code Online (Sandbox Code Playgroud)

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

Set<String> h = new HashSet<String>() {{
    add("a");
    add("b");
}};
Run Code Online (Sandbox Code Playgroud)

  • @DD它是一个黑客,因为它正在创建一个匿名的HashSet内部子类,其静态初始化部分调用add()方法,这对于这种情况肯定是过度的.我喜欢它! (49认同)
  • 双括号初始化是一个非常危险的黑客.匿名类具有到外部类的隐式链接,这可能导致内存泄漏.持有双括号初始化集合的人也拥有创建集合的类. (41认同)
  • @fhucho这个方法在(比如说)JMock中设置模拟对象Expectations非常流行,即使考虑到内存泄漏风险,它在这种情况下也很有意义(测试是内存占用不重要的短期进程). (6认同)

Chr*_*oom 192

在Java 8中我会使用:

Set<String> set = Stream.of("a", "b").collect(Collectors.toSet());
Run Code Online (Sandbox Code Playgroud)

这为您提供了一个可变的Set预初始化"a"和"b".请注意,虽然在JDK 8中这确实返回a HashSet,但规范并不保证它,并且这可能在将来发生变化.如果您特别想要HashSet,请改为:

Set<String> set = Stream.of("a", "b")
                        .collect(Collectors.toCollection(HashSet::new));
Run Code Online (Sandbox Code Playgroud)

  • 这比原始问题中的普通旧代码更加冗长和不必要的复杂. (34认同)
  • @Natix对于2个元素,它更详细,但是如果你必须使用更多元素(10-100s)对集合进行硬编码,这种表示就会变得简洁 (11认同)
  • @Natix是的,但它是内联的,在某些情况下这是一个优势 (4认同)
  • 为什么不是更紧凑的版本:Stream.of(1, 3, 5).collect(toSet()); 它使用 import static java.util.stream.Collectors.toSet; (3认同)
  • 另外,如果你想要一个只有一项的“Set”,可以创建一个“Singleton”:“final Set&lt;T&gt; SOME_SET = Collections.singleton(t);” (3认同)

i_a*_*ero 149

使用Java 10(不可修改集)

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

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

使用Java 9(不可修改集)

Set<String> strSet6 = Set.of("Apple", "Ball", "Cat", "Dog");
Run Code Online (Sandbox Code Playgroud)

我们有12个这种方便工厂方法的重载版本:

Collections.unmodifiableSet()

Collectors.toUnmodifiableSet()

static <E> Set<E> of()

// ....等等

static <E> Set<E> of(E e1)

那么一个自然的问题就是为什么当我们有var-args时我们需要重载版本?答案是:每个var-arg方法在内部创建一个数组,并且具有重载版本将避免不必要的对象创建,并且还将使我们免于垃圾收集开销.

使用Java 8(可修改集)

在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));
Run Code Online (Sandbox Code Playgroud)

使用Java 8(不可修改集)

使用Collections.unmodifiableSet - 我们可以使用static <E> Set<E> of(E e1, E e2)as:

Set<String> strSet4 = Collections.unmodifiableSet(strSet1);
Run Code Online (Sandbox Code Playgroud)

但它看起来有点尴尬,我们可以像这样写我们自己的收藏家:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后将其用作:

Set<String> strSet4 = Stream.of("A", "B", "C", "D")
             .collect(ImmutableCollector.toImmutableSet());
Run Code Online (Sandbox Code Playgroud)

使用Collectors.collectingAndThen - 另一种方法是使用static <E> Set<E> of(E... elems)允许我们执行其他完成转换的方法:

import static java.util.stream.Collectors.*;
Set<String> strSet5 = Stream.of("A", "B", "C", "D").collect(collectingAndThen(
   toCollection(HashSet::new),Collections::unmodifiableSet));
Run Code Online (Sandbox Code Playgroud)

如果我们只关心Collections.unmodifiableSet()那么我们也可以Collectors.collectingAndThen()代替Set.


需要注意的一点是,该方法Collectors.toSet()根据doc返回指定集的不可修改视图.不可修改的视图集合是一个不可修改的集合,也是一个支持集合的视图.请注意,可能仍然可以对支持集合进行更改,如果它们发生,则通过不可修改的视图可以看到它们.但是该方法Collectors.toCollection(HashSet::new)Java 10中返回真正的不可变集.


coo*_*ird 87

有几种方法:

双支撑初始化

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

Set<String> s = new HashSet<String>() {{
    add("a");
    add("b");
}}
Run Code Online (Sandbox Code Playgroud)

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

一种实用方法

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

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

    for (String s : strings) {
        set.add(s);
    }
    return set;
}
Run Code Online (Sandbox Code Playgroud)

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

使用图书馆

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

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

  • GoogleCollections还有`ImmutableSet.of(T ...)`.大多数情况下,在执行此操作时,您不需要稍后再次更改该集,在这种情况下,使用不可变集具有许多优点. (20认同)
  • 澄清*将在每次使用时创建一个新的HashSet子类*,表示"每次*编码*".每个*执行*都*不*创建一个新的子类. (4认同)

Lu5*_*u55 40

如果你只有一个初始值,那就足够了:

Set<String> immutableSet = Collections.singleton("a");
Run Code Online (Sandbox Code Playgroud)

  • 请注意,生成的Set <String>是不可变的. (8认同)

Mic*_*hev 29

最方便的方法之一是使用通用的Collections.addAll()方法,它采用集合和varargs:

Set<String> h = new HashSet<String>();
Collections.addAll(h, "a", "b");
Run Code Online (Sandbox Code Playgroud)

  • 我认为这至少在 Java 5+ 中可用。 (4认同)
  • 谢谢!很高兴我进一步阅读,imo 这应该排名更高。这对于 Java 8 及更低版本非常有用;不要复制数组和笨拙的流。谢谢! (3认同)

Jas*_*ols 27

你可以用Java 6做到这一点:

Set<String> h = new HashSet<String>(Arrays.asList("a", "b", "c"));
Run Code Online (Sandbox Code Playgroud)

但为什么?我没有发现它比显式添加元素更具可读性.

  • 啊.值得注意的是,您仍然可以将元素添加到最终集合中.只需声明set final,但可以像往常一样在构造函数(或其他任何地方)中添加元素.最终的Collection仍然可以添加或删除元素.如果最终的话,只有对Collection本身的引用. (18认同)
  • 我在声明中创建它.这是最后的财产.谢谢 (5认同)
  • +1杰森尼科尔斯说的话.不要忘记使用Collections.unmodifiableSet(...). (5认同)

Mat*_*der 27

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

Set.of("a", "b");
Run Code Online (Sandbox Code Playgroud)

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

  • 如今,这显然是最好的答案。确实,所有其他信息仅用于提供信息,而不用于使用。 (2认同)

Lan*_*ceP 24

我觉得最可读的是简单地使用谷歌番石榴:

Set<String> StringSet = Sets.newSet("a", "b", "c");
Run Code Online (Sandbox Code Playgroud)

  • 现在是`Sets.newHashSet()`. (6认同)

Mar*_*iot 14

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

public static <T> Set<T> newHashSet(T... objs) {
    Set<T> set = new HashSet<T>();
    for (T o : objs) {
        set.add(o);
    }
    return set;
}
Run Code Online (Sandbox Code Playgroud)


Her*_*eri 13

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

Set<MY_ENUM> MY_SET = EnumSet.of( MY_ENUM.value1, MY_ENUM.value2, ... );
Run Code Online (Sandbox Code Playgroud)


Bry*_*ell 6

import com.google.common.collect.Sets;
Sets.newHashSet("a", "b");
Run Code Online (Sandbox Code Playgroud)

要么

import com.google.common.collect.ImmutableSet;
ImmutableSet.of("a", "b");
Run Code Online (Sandbox Code Playgroud)


Don*_*aab 5

使用Eclipse Collections,有几种不同的方法可以Set在一个语句中初始化包含字符"a"和"b"的字符串.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();
Run Code Online (Sandbox Code Playgroud)

Eclipse Collections与Java 5 - 8兼容.

注意:我是Eclipse Collections的提交者.


Nam*_*man 5

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

Set set = Set.of("a", "b", "c");
Run Code Online (Sandbox Code Playgroud)