Вопрос

Мне нужно создать 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));

Немного менее уродливая и эффективность не имеет значения для статической инициализации.

Другие советы

Литералы сбора были запланированы на 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 предварительно инициализированный с «А» и «B». Обратите внимание, что в JDK 8 это возвращает HashSet, Спецификация не гарантирует это, и это может измениться в будущем. Если вам специально хотите HashSet, сделайте это вместо этого:

Set<String> set = Stream.of("a", "b")
                        .collect(Collectors.toCollection(HashSet::new));

Использование Java 10 (немодифицируемые наборы)

Set<String> strSet1 = Stream.of("A", "B", "C", "D")
         .collect(Collectors.toUnmodifiableSet());

Здесь коллекционер фактически вернет немодиажирующий набор, введенный в Java 9, как видно из заявления set -> (Set<T>)Set.of(set.toArray()) в исходном коде.

Один момент, чтобы отметить это метод Collections.unmodifiableSet() Возвращает немодиажируемое представление указанного набора (согласно документации). Атмосфера немодизируемый вид Коллекция - это коллекция, которая не поддается немодиации, а также является представлением на коллекцию поддержки. Обратите внимание, что изменения в коллекции поддержки мощь Все еще будьте возможны, и если они возникают, они видны с помощью немодиажируемого представления. Но метод Collectors.toUnmodifiableSet() возврат Поистине неизменно установить Java 10.


Использование Java 9 (немодифицируемые наборы)

Ниже приводится самый компактный способ инициализации набора:

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 создает массив внутри внутреннего, и наличие перегруженных версий избежат ненужного создания объекта, а также спасет нас от накладных расходов сбора мусора.


Использование 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 (немодифицируемые наборы)

Использование collections.unmodifableset ()

Мы можем использовать 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());


Использование collectors.collingandThen ()

Другой подход - использовать метод 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).

Есть несколько способов:

Двойная инициализация скобок

Это техника, которая создает анонимный внутренний класс, который имеет инициализатор экземпляра, который добавляет StringS к себе, когда создается экземпляр:

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 имеет Sets.newHashSet(T...) метод, который будет заполнять HashSet с элементами определенного типа.

Если у вас есть только одно значение и вы хотите получить неизменный Установить этого было бы достаточно:

Set<String> immutableSet = Collections.singleton("a");

Один из самых удобных способов - использование общего Collections.addall () Метод, который берет на себя коллекцию и Varargs:

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

Вы можете сделать это в Java 6:

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

Но почему? Я не считаю, что это более читабельным, чем явно добавляя элементы.

Я чувствую, что наиболее читаемо - просто использовать Google Guava:

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

С Java 9 вы можете сделать следующее:

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

И вы получите неизменную набор, содержащий элементы. Для получения подробной информации см. Oracle Документация набора интерфейса.

Обобщение Ответ COBIRD функция полезности для создания новых HashSetS:

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

Если содержащий тип набора является перечислением, то есть фабричный метод, основанный на Java (с 1,5):

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

С Коллекции затмения Есть несколько разных способов инициализации 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");

(уродливая) инициализация двойной скобы без побочных эффектов:

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

Просто небольшая нота, независимо от того, с каким из точных подходов, упомянутых здесь, вы в конечном итоге, если это по умолчанию, которое обычно не остается неизменным (например, настройка по умолчанию в библиотеке, которую вы создаете), это хорошая идея, чтобы следовать этому шаблону :

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

С выпуском и Удобные фабричные методы Это возможно более чистым образом:

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

Узор застройщика может быть полезен здесь. Сегодня у меня была такая же проблема. где мне нужно было установить операции мутации, чтобы вернуть мне ссылку на установленную объект, чтобы я мог передать его в супер -класс конструктор, чтобы они тоже могли продолжать добавлять в тот же набор, в свою очередь, построив новый строки из набора, что у ребенка класс дочерних только что построенный. Класс строителей, который я написал, выглядит так (в моем случае это статический внутренний класс внешнего класса, но это может быть и его собственный независимый класс):

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

Объединение ответа Майкл Бердишев с дженериками и с использованием конструктора с начальной силой, сравнивая с 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
  }
  • Это хорошо, если вы передаете несколько значений для init, для чего -либо большого использования других методов
  • Если вы случайно смешиваете типы с buildSetModif Получившись t будет ? extends Object, что, вероятно, не то, что вы хотите, это не может произойти с buildSetModifTypeSafe вариант, что означает, что buildSetModifTypeSafe(1, 2, "a"); не будет компилировать
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top