关于java:如何通过构造初始化HashSet值?

How to initialize HashSet values by construction?

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

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

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


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

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

同样,这是不省时的,因为您正在构造一个数组,转换为一个列表,并使用该列表创建一个集合。

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

1
2
public static final String[] SET_VALUES = new String[] {"a","b" };
public static final Set<String> MY_SET = new HashSet<>(Arrays.asList(SET_VALUES));

稍微不那么难看,效率对于静态初始化来说并不重要。


集合文字是为Java 7调度的,但没有实现。所以还没有自动的。

您可以使用Guava的Sets

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

或者,您可以使用以下语法,这将创建一个匿名类,但这是黑客行为:

1
2
3
4
Set<String> h = new HashSet<String>() {{
    add("a");
    add("b");
}};


在Java 8中,我将使用:

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

这将给您一个可变的Set预初始化为"a"和"b"。注意,在JDK8中,虽然它返回了一个HashSet,但是规范并不能保证它,而且将来可能会发生变化。如果您特别想要一个HashSet,请执行以下操作:

1
2
Set<String> set = Stream.of("a","b")
                        .collect(Collectors.toCollection(HashSet::new));


使用爪哇10(不可更改组件)

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

在这里,收集器将实际返回不可更改的组件在爪哇9号作为声明set -> (Set)Set.of(set.toArray())在源代码。

使用爪哇9(不可更改组件)ZZU1

We have 12 overloaded versions of this convenience factory method:

static Set of()

static Set of(E e1)

static Set of(E e1, E e2)

// ....and so on

static Set of(E... elems)

那么,一个自然的问题是,为什么我们需要过多的版本,当我们变了。答案是:每一个Var-Arg方法创建一个内部阵列,并且有过多的负载版本,可以避免不必要的对象创建,并且也可以将我们从收藏在头顶上。

使用Java 8(可修改组件)

使用爪哇流域

1
2
3
4
5
6
7
8
9
10
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));

Using Java 8(Unmodible sets)

Using collections.unmodifiableset-we can use Collections.unmodifiableSetas:

1
Set<String> strSet4 = Collections.unmodifiableSet(strSet1);

但它看起来很慢,我们可以写我们自己的收藏家

1
2
3
4
5
6
7
8
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);
    }
}

然后用作:

1
2
Set<String> strSet4 = Stream.of("A","B","C","D")
             .collect(ImmutableCollector.toImmutableSet());

Using collectors.collectingandthen-another approach is to use the method Collectors.collectingAndThenwhich letts us perform additional finishing transformations:

1
2
3
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返回一个不可更改的视图,如每一个文件。一个不可更改的视图集是一个不可更改的收藏,也是一个向后看的收藏。注意到后面的收藏可能仍有可能发生变化,如果出现这种情况,则通过不可改变的视野可以看到。但方法是在爪哇真的不可回收


有几种方法:

双括号初始化

这是一种创建匿名内部类的技术,该类具有实例初始值设定项,在创建实例时将Strings添加到自身:

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

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

一种实用方法

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

1
2
3
4
5
6
7
8
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


如果集合中只有一个初始值,这就足够了:

1
Set<String> h = Collections.singleton("a");


你可以在Java 6中完成:

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

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


2.One of the most convenient ways is using of generic collections.addall()method,which takes a collection and varargs:

1
2
Set<String> h = new HashSet<String>();
Collections.addAll(h,"a","b");


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

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


With Java 9 you can do the following:

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

你会得到一个不可磨灭的组件For details see the Oracle documentation of interface set.


coobird's answer's utility函数在创建新HashSets中的推广:

1
2
3
4
5
6
7
public static <T> Set<T> newHashSet(T... objs) {
    Set<T> set = new HashSet<T>();
    for (T o : objs) {
        set.add(o);
    }
    return set;
}

如果集合的包含类型是枚举,则有Java构建的工厂方法(自1.5以来):

1
Set<MY_ENUM> MY_SET = EnumSet.of( MY_ENUM.value1, MY_ENUM.value2, ... );

对于Eclipse集合,有几种不同的方法来初始化Set,其中一条语句中包含字符"a"和"b"。Eclipse集合同时具有对象和原语类型的容器,因此我演示了如何使用SetCharSet,以及它们的可变、不可变、同步和不可修改版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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集合与Java 5 - 8兼容。

注意:我是Eclipse集合的提交者。


1
2
import com.google.common.collect.Sets;
Sets.newHashSet("a","b");

黄金

1
2
import com.google.common.collect.ImmutableSet;
ImmutableSet.of("a","b");


有点复杂,但从Java 5工作:

1
2
3
Set<String> h = new HashSet<String>(Arrays.asList(new String[] {  
   "a","b"
}))

使用助手方法使其可读:

1
2
3
4
5
Set<String> h = asSet ("a","b");

public Set<String> asSet(String... values) {
    return new HashSet<String>(java.util.Arrays.asList(values));
}


(Ugly)Double Brace initiatization without side effects:

1
2
3
4
Set<String> a = new HashSet<>(new HashSet<String>() {{
    add("1");
    add("2");
}})

但在某些情况下,如果我们说谎是一种很好的烟雾,使最终的收藏无法变形,那么它可能是真正的使用:

1
2
3
4
final Set<String> a = Collections.unmodifiableSet(new HashSet<String>(){{
    add("1");
    add("2");
}})

使用爪哇8我们可以创造HashSet

1
Stream.of("A","B","C","D").collect(Collectors.toCollection(HashSet::new));

如果我们想要一个不可更改的设置,我们可以创造一个有效的方法,例如:

1
2
3
4
5
6
7
8
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);
    }

This method can be used as:

1
 Stream.of("A","B","C","D").collect(toImmutableSet(HashSet::new));

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

1
2
3
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;

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

如果您决定遵循这个模式,那么您还可以选择最可读的set初始化方法。由于不同方法之间效率的细微差别可能无关紧要,因为您将只初始化一次集合。


With the release of Java9 and the convenience factory methods this is possible in a cleaner way:

1
Set set = Set.of("a","b","c");


Can use static block for initiatization:

1
2
3
4
5
6
7
8
9
10
11
12
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);
}

这是一个优雅的解决方案:

1
2
3
4
5
6
7
8
9
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);
            }
        };
}


建筑物模式可能在这里使用。今天我也有同样的问题。在我需要做突变手术的地方,我可以把它交给超级阶级制造商,所以他们也可以继续把同样的一个设置,转动一个新的弦结构,摆脱那一组的孩子。建筑物阶级我写的样子(以我为例,它是一个静态的内在阶级,但它可以是它自己的独立阶级和它自己):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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;
    }
}

《经济、社会、文化权利国际公约》第1条和《经济、社会、文化权利国际公约》第1条的通知最后,方法说明了建筑物封装的一个参照点。Below includerates then how to use this set builder:

1
2
3
4
5
6
7
8
9
10
11
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());
    }
}