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

时间:2010-01-11 12:31:51

标签: java collections constructor initialization hashset

我需要创建一个带有初始值的Set

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

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

24 个答案:

答案 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)

使用Java 10(不可修改集)

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

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

使用Java 9(不可修改集)

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(可修改集)

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

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

需要注意的一点是方法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 CollectionsSets.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)

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

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

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

答案 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)

随着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
  }
  • 如果您为init传递了一些值,对于任何大的值,这都很好 使用其他方法
  • 如果您不小心将类型与buildSetModif混合使用,则结果T将 是? extends Object,可能不是您想要的,而buildSetModifTypeSafe变体就不会发生,这意味着buildSetModifTypeSafe(1, 2, "a");无法编译

答案 23 :(得分:0)

您也可以使用vavr

import io.vavr.collection.HashSet;

HashSet.of("a", "b").toJavaSet();