Мне нужно создать Set
с начальными значениями.
Set<String> h = new HashSet<String>();
h.add("a");
h.add("b");
Есть ли способ сделать это одной строкой кода? Например, это полезно для финального статического поля.
Мне нужно создать Set
с начальными значениями.
Set<String> h = new HashSet<String>();
h.add("a");
h.add("b");
Есть ли способ сделать это одной строкой кода? Например, это полезно для финального статического поля.
Я использую сокращенную запись, которая не очень эффективна по времени, но умещается в одной строке:
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));
Немного менее уродливый и эффективность не имеет значения для статической инициализации.
Set<String> h = Set.of("a", "b") //Unmodifiable
Этот ответ актуален
- person Mauve Ranger; 02.07.2018
Литералы коллекции были запланированы для Java 7, но не вошли. Так что пока ничего автоматического.
Вы можете использовать _1 _ а>:
Sets.newHashSet("a", "b", "c")
Или вы можете использовать следующий синтаксис, который создаст анонимный класс, но он хакерский:
Set<String> h = new HashSet<String>() {{
add("a");
add("b");
}};
Если вы ищете наиболее компактный способ инициализации набора, то это было в Java9
:
Set<String> strSet = Set.of("Apple", "Ball", "Cat", "Dog");
===================== Подробный ответ ниже ========================== =======
Set<String> strSet1 = Stream.of("A", "B", "C", "D")
.collect(Collectors.toUnmodifiableSet());
Здесь сборщик фактически вернет неизменяемый набор, представленный в Java 9, как видно из оператора set -> (Set<T>)Set.of(set.toArray())
в исходном коде.
Следует отметить, что метод _ 5_ возвращает неизменяемое представление указанного набора (согласно документации). Коллекция неизменяемых представлений - это неизменяемая коллекция, которая также является представлением для вспомогательной коллекции. Обратите внимание, что изменения в фоновой коллекции могут по-прежнему возможны, и если они происходят, они видны в неизменяемом представлении. Но метод _6 _ возвращает действительно неизменяемый, установленный в Java 10.
Ниже приводится самый компактный способ инициализации набора:
Set<String> strSet6 = Set.of("Apple", "Ball", "Cat", "Dog");
У нас есть 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 создает массив внутри, и наличие перегруженных версий позволит избежать ненужного создания объекта, а также избавит нас от накладных расходов на сборку мусора.
Использование Stream в Java 8.
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));
Мы можем использовать 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());
import static java.util.stream.Collectors.*;
Set<String> strSet5 = Stream.of("A", "B", "C", "D").collect(collectingAndThen(
toCollection(HashSet::new),Collections::unmodifiableSet));
Если нас интересует только Set
, мы также можем использовать _ 19_ вместо Collectors.toCollection(HashSet::new)
.
В 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));
Set
только с одним элементом, можно создать Singleton
: final Set<T> SOME_SET = Collections.singleton(t);
- person Valentin Grégoire; 09.07.2019
Есть несколько способов:
Инициализация двойной скобки
Это метод, который создает анонимный внутренний класс, который имеет инициализатор экземпляра, который добавляет к себе String
s при создании экземпляра:
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 Collections есть _ 7_, который заполнит HashSet
элементы определенного типа.
ImmutableSet.of(T...)
. В большинстве случаев при этом вам не нужно снова менять набор позже, и в этом случае использование неизменяемого набора имеет много преимуществ.
- person Kevin Bourrillion; 11.01.2010
Один из наиболее удобных способов - использовать общий Collections.addAll (), который принимает коллекцию и переменные:
Set<String> h = new HashSet<String>();
Collections.addAll(h, "a", "b");
Если у вас есть только одно значение и вы хотите получить неизменяемый набор, этого будет достаточно:
Set<String> immutableSet = Collections.singleton("a");
new HashSet<>(Arrays.asList( _values_ ))
только с одним значением.
- person yokeho; 29.08.2017
С Java 9 вы можете делать следующее:
Set.of("a", "b");
и вы получите неизменный Set, содержащий элементы. Подробнее см. документацию по интерфейсу Set Oracle. .
Вы можете сделать это в Java 6:
Set<String> h = new HashSet<String>(Arrays.asList("a", "b", "c"));
Но почему? Я не считаю его более читабельным, чем явное добавление элементов.
new HashSet<String>("a", "b", "c");
- person sam boosalis; 18.04.2014
Я считаю, что наиболее удобочитаемым является использование google Guava:
Set<String> StringSet = Sets.newHashSet("a", "b", "c");
Это изменчиво.
Sets.newHashSet()
.
- person membersound; 01.03.2016
Обобщение вспомогательной функции ответа от coobird для создания новых HashSet
s:
public static <T> Set<T> newHashSet(T... objs) {
Set<T> set = new HashSet<T>();
for (T o : objs) {
set.add(o);
}
return set;
}
Если содержащийся тип Set является перечислением, тогда существует встроенный фабричный метод java (начиная с версии 1.5):
Set<MY_ENUM> MY_SET = EnumSet.of( MY_ENUM.value1, MY_ENUM.value2, ... );
В Eclipse Collections есть несколько различных способов инициализировать Set
, содержащий символы 'a' и ' b 'в одном заявлении. В Eclipse Collections есть контейнеры как для объектных, так и для примитивных типов, поэтому я проиллюстрировал, как можно использовать Set<String>
или _ 3_ в дополнение к изменяемым, неизменяемым, синхронизированным и неизменяемым версиям обоих.
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.
(уродливо) Инициализация двойной скобки без побочных эффектов:
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");
}})
Немного запутано, но работает с 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));
}
new String[] {
)
- person Kevin Bourrillion; 11.01.2010
Небольшое примечание, независимо от того, какой из упомянутых здесь подходов вы получите, если это значение по умолчанию, которое обычно остается неизменным (например, настройка по умолчанию в создаваемой вами библиотеке), рекомендуется следовать этому шаблону. :
// 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;
Преимущество зависит от количества созданных вами экземпляров этого класса и от того, насколько вероятно, что значения по умолчанию будут изменены.
Если вы решите следовать этому шаблону, вы также можете выбрать наиболее читаемый метод инициализации набора. Поскольку микроразличия в эффективности между различными методами, вероятно, не будут иметь большого значения, поскольку вы инициализируете набор только один раз.
Используя 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));
С выпуском java9 и удобные фабричные методы, это возможно более чистым способом:
Set set = Set.of("a", "b", "c");
Можно использовать статический блок для инициализации:
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);
}
Это элегантное решение:
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);
}
};
}
Здесь может пригодиться паттерн Строитель. Сегодня у меня была такая же проблема. где мне нужны операции изменения Set, чтобы вернуть мне ссылку на объект Set, поэтому я могу передать его конструктору суперкласса, чтобы они тоже могли продолжать добавлять в тот же набор, в свою очередь создавая новый StringSetBuilder из набора, который дочерний класс только что построен. Написанный мною класс строителя выглядит следующим образом (в моем случае это статический внутренний класс внешнего класса, но он также может быть его собственным независимым классом):
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 возвращают аналоги 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());
}
}
Комбинируя ответ Михаила Бердышева с Generics и используя конструктор с 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
}
buildSetModif
, в результате T будет ? extends Object
, что, вероятно, не то, что вы хотите, этого не может произойти с вариантом buildSetModifTypeSafe
, а это означает, что buildSetModifTypeSafe(1, 2, "a");
не будет компилироватьсяВы также можете использовать vavr:
import io.vavr.collection.HashSet;
HashSet.of("a", "b").toJavaSet();