创建集合时添加元素

32

我应该如何在Java中创建一个Set,然后在构造时向其中添加对象。我希望做的事情像这样:

testCollision(getObject(), new HashSet<MazeState>(){add(thing);});

但是那似乎不完全正确。

7个回答

71
自从 Java 7 开始,要实例化一个单元素不可变的 Set,可以使用以下代码:
Collections.singleton(thing);

返回一个包含指定对象的不可变集合。返回的集合是可序列化的。 — Javadoc reference: Collections.singleton(T)
在Java 8中,您可以使用以下代码实例化一个包含任意数量对象的Set,这是此答案的改编版本:
Stream.of(thing, thingToo).collect(Collectors.toSet());

28

3
考虑使用Collections.singletonList方法。 - Sebastian Kramer

24

自 Java 9 起,您也可以这样做:

 Set<String> immutableSet = Set.of("value1", "value2");
 Set<Integer> immutableInt = Set.of(1, 2);

 List<String> immutableList = List.of("item1", "item2");

 Map<String, String> immutableMap = Map.of("key1", "value1", "key2", "value2", "key3", "value3");
请注意,用这种方式创建的任何集合/映射表/列表都是不可变的(如果我的命名约定没有说服你的话;)

为什么你不是第一个? - Joaquín L. Robles

17
您可以使用双大括号语法:
testCollision(getObject(), new HashSet<MazeState>(){{ add(obj1); add(obj2);}};
或:
Set<String> set = new HashSet<String>(){{
  add("hello");
  add("goodbye");
}};
这被称为双括号初始化,它是 Java 的较为不知名的特性之一。其作用是让编译器为您创建一个匿名内部类来完成对象的创建和操作(例如,如果您的类是 final 类,您就不能使用它)。
现在,话虽如此 - 我建议您只在真正需要简洁的情况下使用它。通常最好更明确地表达代码,以便更容易理解。

4
“双括号初始化”不完全是一个“特性”:它并非有意引入。它只是初始化块和匿名类的巧妙运用。也许过于巧妙了 :) - Nikita Rybak
2
双括号初始化还会导致一个类的子类被创建,如果你在其他地方错误地依赖于实际的类,这可能会消耗内存并导致意外的失败。话虽如此,我在我的测试代码中经常使用双括号初始化,因为这样非常清楚正在发生什么,而且我不需要担心内存等问题。 - RHSeeger
1
IntelliJ的警告补充了上面提到的警告。双括号初始化在非静态上下文中使用时可能会导致内存泄漏,因为创建的匿名类将保留对周围对象的引用。与常规初始化相比,它具有更差的性能,因为需要额外的类加载。如果equals()方法不接受子类作为参数,则可能导致equals()比较失败(请参见上面的链接)。最后,在Java 9之前,它不能与菱形操作符组合使用,因为不能与匿名类一起使用。 - Mark Jeronimus

8

仅供参考,此方法来自Google Guava库,而不是标准JDK。Guava有很多非常好的功能值得一试,但如果你只想要这个方法,那么请注意你正在导入一个庞大的库。 - Stormcloud

5
你可以使用来自com.google.common.collect的util方法,它非常不错:Sets.newHashSet("你的值1", "你的值2");

少数几个答案之一,不会强制你走向不可变的道路。 - Nikita Rybak

1

其他答案都是正确的,但我想再补充一种方法。使用初始化块

new HashSet<MazeState>() {

            {
                add(new MazeState());
                add(new MazeState());
            }
        };

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接