首页 文章

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

提问于
浏览
568

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

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

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

22 回答

  • 23

    随着java9convenience factory methods的发布,这可以更清洁的方式:

    Set set2 = Set.of("a", "b", "c");
    
  • 160

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

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

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

  • 14

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

    你可以使用guava的Sets

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

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

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

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

    有几种方法:

    Double brace initialization

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

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

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

    A utility method

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

    public static Set<String> newHashSet(String... strings) {
        HashSet<String> set = new HashSet<String>();
    
        for (String s : strings) {
            set.add(s);
        }
        return set;
    }
    

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

    Use a library

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

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

  • 2

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

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

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

    Using 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) .


    One point to note 是方法 Collections::unmodifiableSet 返回指定集的不可修改视图,如doc . 不可修改的视图集合是一个不可修改的集合,也是一个支持集合的视图 . 请注意,可能仍然可以对支持集合进行更改,如果它们发生,则通过不可修改的视图可以看到它们 . 但方法 Collectors.unmodifiableSetJava 10 中返回真正的不可变集 .

  • 18

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

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

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

  • 5

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

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

    我觉得最可读的就是简单地使用谷歌 Guava :

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

    最方便的方法之一是使用泛型Collections.addAll()方法,该方法采用集合和变量:

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

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

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

    你会得到一个包含元素的不可变集合 . 有关详细信息,请参阅Oracle documentation of interface Set .

  • 0

    用于创建新 HashSetcoobird's answer's实用函数的推广:

    public static <T> Set<T> newHashSet(T... objs) {
        Set<T> set = new HashSet<T>();
        for (T o : objs) {
            set.add(o);
        }
        return set;
    }
    
  • 81

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

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

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

  • 4
    import com.google.common.collect.Sets;
    Sets.newHashSet("a", "b");
    

    要么

    import com.google.common.collect.ImmutableSet;
    ImmutableSet.of("a", "b");
    
  • 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));
    }
    
  • 26

    (丑陋)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");
    }})
    
  • 9

    只是一个小小的注释,无论这里提到哪种精细方法如果这是一个通常未经修改的默认设置(如您正在创建的库中的默认设置),最终会遵循以下模式:

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

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

    如果您决定遵循此模式,那么您还可以选择最易读的集初始化方法 . 由于不同方法之间效率的微观差异可能无关紧要,因为您只需初始化一次 .

  • 5

    使用 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));
    
  • 3

    可以使用静态块进行初始化:

    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);
    }
    
  • 18

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

    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

    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构建器:

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

相关问题