Как инициализировать значения HashSet по конструкции?
мне нужно создать Set
с начальными значениями.
Set<String> h = new HashSet<String>();
h.add("a");
h.add("b");
есть ли способ сделать это в одну строку кода?
22 ответов
есть стенография, которую я использую, которая не очень эффективна во времени, но подходит для одной строки:
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));
немного менее уродливый и эффективность не имеет значения для статической инициализации.
литералы коллекции были запланированы для Java 7,но не сделали этого. Пока ничего автоматического.
вы можете использовать гуава это Sets
:
Sets.newHashSet("a", "b", "c")
или вы можете использовать следующий синтаксис, который позволит создать анонимный класс, но суховато:
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));
есть несколько способов:
двойной дубль инициализации
это метод, который создает анонимный внутренний класс, который имеет инициализатор экземпляра, который добавляет String
s для себя при создании экземпляра:
Set<String> s = new HashSet<String>() {{
add("a");
add("b");
}}
имейте в виду, что это фактически создаст новый подкласс HashSet
каждый раз, когда он используется, даже если не нужно явно писать новый подкласс.
A метод полезности
написание метода, который возвращает 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 Коллекции есть Sets.newHashSet(T...)
метод, который будет заполнять HashSet
С ЭЛЕМЕНТАМИ определенного типа.
Использование 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.
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 (Немодифицируемые Наборы)
использование Коллекции.unmodifiableSet - мы можем использовать Collections.unmodifiableSet
as:
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());
С Помощью Коллекторов.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)
.
одно замечание это и есть метод Collections::unmodifiableSet
возвращает неизменяемое представление указанного набора в соответствии с doc. Немодифицируемая коллекция представлений-это немодифицируемая коллекция, а также представление резервной коллекции. Обратите внимание, что изменения в резервной коллекции все еще могут быть возможны, и если они происходят, они видны через немодифицируемое представление. Но метод Collectors.unmodifiableList
возвращает по-настоящему неизменяемый набор в Java 10.
вы можете сделать это в Java 6:
Set<String> h = new HashSet<String>(Arrays.asList("a", "b", "c"));
но почему? Я не нахожу его более читаемым, чем явное добавление элементов.
Если у вас есть только одно начальное значение в наборе, этого будет достаточно:
Set<String> h = Collections.singleton("a");
Я чувствую, что наиболее читаемым является просто использовать google Guava:
Set<String> StringSet = Sets.newSet("a", "b", "c");
С Java 9 вы можете сделать следующее:
Set.of("a", "b");
и вы получите неизменяемый набор, содержащий элементы. Подробнее см. В разделе Oracle документация набора интерфейса.
одним из наиболее удобных способов является использование generic сборники.addAll () метод, который принимает коллекцию и varargs:
Set<String> h = new HashSet<String>();
Collections.addAll(h, "a", "b");
обобщение 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;
}
если содержащийся тип набора является перечислением, то существует Java built factory method (начиная с 1.5):
Set<MY_ENUM> MY_SET = EnumSet.of( MY_ENUM.value1, MY_ENUM.value2, ... );
С Коллекции Eclipse существует несколько различных способов инициализации Set
содержащий символы " a " и " b " в одном операторе. Коллекции Eclipse имеют контейнеры как для объектов, так и для примитивных типов, поэтому я проиллюстрировал, как вы можете использовать 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.
import com.google.common.collect.Sets;
Sets.newHashSet("a", "b");
или
import com.google.common.collect.ImmutableSet;
ImmutableSet.of("a", "b");
немного запутанный, но работает с 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));
}
(уродливый) двойная инициализация скобки без побочных эффектов:
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");
}})
просто небольшая заметка, независимо от того, какой из тонких подходов, упомянутых здесь, вы в конечном итоге, если это значение по умолчанию, которое обычно остается неизменным (например, настройка по умолчанию в создаваемой библиотеке), рекомендуется следовать этому шаблону:
// 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;
преимущество зависит от количества экземпляров, которые вы создаете этого класса и насколько вероятно, что значения по умолчанию будут изменены.
Если вы решили следовать этому шаблону, то вы также можете выбрать метод установите инициализацию, которая наиболее удобочитаема. Поскольку микро-различия в эффективности между различными методами, вероятно, не будут иметь большого значения, поскольку вы будете инициализировать набор только один раз.
с выделением java9 и удобство методами производства это возможно более чистым способом, как:
Set set2 = Set.of("a", "b", "c");
используя Java 8 мы можем создать HashSet
as:
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));
можно использовать статический блок инициализации:
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);
}
};
}
шаблон Builder может быть полезен здесь. Сегодня у меня была та же проблема. где мне нужно было установить операции мутации, чтобы вернуть мне ссылку на объект 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.add()
и Set.addAll()
. Наконец, обратите внимание на build()
метод, который возвращает ссылку на набор строитель инкапсулирует. Ниже показано, как использовать этот конструктор наборов:
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());
}
}