如何通过构造来初始化HashSet值?
我需要用初始值创build一个Set
。
Set<String> h = new HashSet<String>(); h.add("a"); h.add("b");
有没有办法在一行代码中做到这一点?
有一个速记,我用它不是非常省时,但适合在一个单一的线上:
Set<String> h = new HashSet<>(Arrays.asList("a", "b"));
同样,这是不是时间效率,因为你正在构build一个数组,转换为一个列表,并使用该列表来创build一个集合。
初始化静态最终集时,我通常会这样写:
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,但没有进入。所以没有自动呢。
你可以使用番石榴的Sets
:
Sets.newHashSet("a", "b", "c")
或者你可以使用下面的语法,这将创build一个匿名类,但它是hacky:
Set<String> h = new HashSet<String>() {{ add("a"); add("b"); }};
在Java 8中,我将使用:
Set<String> set = Stream.of("a", "b").collect(Collectors.toSet());
这给你一个可变的Set
用“a”和“b”预先初始化。 请注意,在JDK 8中,这确实会返回一个HashSet
,但规范并不能保证它,这在将来可能会改变。 如果你特别想要一个HashSet
,可以这样做:
Set<String> set = Stream.of("a", "b") .collect(Collectors.toCollection(HashSet::new));
有几种方法:
双大括号初始化
这是一种创build匿名内部类的方法,它有一个实例初始化程序,在创build实例时将String
添加到自身:
Set<String> s = new HashSet<String>() {{ add("a"); add("b"); }}
请记住,每次使用HashSet
时,实际上都会创build一个新的子类,即使不需要显式地写一个新的子类。
一种实用方法
编写一个返回一个用所需元素初始化的Set
的方法并不难写:
public static Set<String> newHashSet(String... strings) { HashSet<String> set = new HashSet<String>(); for (String s : strings) { set.add(s); } return set; }
上面的代码只允许使用String
,但是允许使用generics的任何types都不是太困难。
使用图书馆
许多库有一个方便的方法来初始化集合对象。
例如, Google Collections具有Sets.newHashSet(T...)
方法,该方法将使用特定types的元素填充HashSet
。
你可以在Java 6中做到这一点:
Set<String> h = new HashSet<String>(Arrays.asList("a", "b", "c"));
但为什么? 我不觉得它比明确添加元素更可读。
使用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
的选项:
Set<String> strSet4 = Collections.unmodifiableSet(strSet1);
但看起来有些尴尬,我们可以这样写我们自己的collections家:
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::unmodifiableSet); } }
然后用它作为:
Set<String> strSet4 = Stream.of("Apple", "Ball", "Cat", "Dog") .collect(ImmutableCollector.toImmutableSet());
使用Java 9(不可修改集)
Set<String> strSet5 = Set.of("Apple", "Ball", "Cat", "Dog");
如果你在集合中只有一个初始值就足够了:
Set<String> h = Collections.singleton("a");
我觉得最可读的是简单地使用谷歌番石榴:
Set<String> StringSet = Sets.newSet("a", "b", "c");
coobird的答案用于创build新的HashSet
的效用函数的推广:
public static <T> Set<T> newHashSet(T... objs) { Set<T> set = new HashSet<T>(); for (T o : objs) { set.add(o); } return set; }
最方便的方法之一是使用通用的Collections.addAll()方法,该方法需要一个集合和可变参数:
Set<String> h = new HashSet<String>(); Collections.addAll(h, "a", "b");
如果Set的包含types是一个枚举,则存在java构build的工厂方法(自1.5开始):
Set<MY_ENUM> MY_SET = EnumSet.of( MY_ENUM.value1, MY_ENUM.value2, ... );
使用Eclipse集合有几种不同的方法来初始化包含字符'a'和'b'的Set
在一个语句中。 Eclipse集合包含对象和基本types的容器,所以我说明了除了两者的可变,不可变,同步和不可修改版本以外,如何使用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集合与Java 5 – 8兼容。
注意:我是Eclipse集合的提交者。
使用Java 9,您可以执行以下操作:
Set.of("a", "b");
你会得到一个包含元素的不可变的Set。 有关详情,请参阅此链接 。
有点令人费解,但从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)); }
请注意,无论您最终提到的是哪种方法,如果这是一个默认设置(通常不会被修改)(如您正在创build的库中的默认设置),最好遵循此模式:
// 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;
好处取决于您创build该类的实例的数量,以及更改默认值的可能性。
如果你决定遵循这个模式,那么你也可以select最具可读性的设置初始化方法。 由于不同方法之间效率的微小差异可能无关紧要,因为您只需要初始化一次即可。
import com.google.common.collect.Sets; Sets.newHashSet("a", "b");
要么
import com.google.common.collect.ImmutableSet; ImmutableSet.of("a", "b");
(丑)双Brace初始化没有副作用:
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"); }})
随着java9和便捷工厂方法的发布,这可以以更简洁的方式进行:
Set set2 = Set.of("a", "b", "c");
这是一个优雅的解决scheme:
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); } }; }
可以使用静态块进行初始化:
private static Set<Integer> codes1= new HashSet<Integer>(Arrays.asList(new Integer[] { 1, 2, 3, 4})); private static Set<Integer> codes2 = new HashSet<Integer>(Arrays.asList(new Integer[] { 5, 6, 7, 8})); private static Set<Integer> h = new HashSet<Integer>(); static{ h.add(codes1); h.add(codes2); }
Builder模式可能在这里使用。 今天我有同样的问题。 在哪里我需要设置变异操作返回给我的Set对象的引用,所以我可以将它传递给超类的构造函数,以便他们也可以继续添加到相同的集合,依次构build一个新的StringSetBuilderclosures设置子类刚刚build成。 我写的构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返回Set.add()
和Set.addAll()
。 最后注意build()
方法,它返回对构build器封装的Set的引用。 下面说明如何使用这个Set构build器:
class ChildClass { 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()); } }