Как инициализировать значения HashSet по построению? - PullRequest
651 голосов
/ 11 января 2010

Мне нужно создать Set с начальными значениями.

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

Есть ли способ сделать это в одной строке кода? Например, это полезно для окончательного статического поля.

Ответы [ 23 ]

0 голосов
/ 27 мая 2019

Объединение ответа Михаила Бердышева с помощью 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
  }
  • Это хорошо, если вы передаете несколько значений для init, для чего-либо большого использовать другие методы
  • Если вы случайно смешаете типы с buildSetModif, результирующий T будет быть ? extends Object, что, вероятно, не то, что вы хотите, это не может произойти с вариантом buildSetModifTypeSafe, означающим, что buildSetModifTypeSafe(1, 2, "a"); не будет компилироваться
0 голосов
/ 03 ноября 2017

Здесь может пригодиться шаблон 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, который инкапсулирует построитель. Ниже показано, как использовать этот конструктор множеств:

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());
    }
}
0 голосов
/ 12 мая 2015

Это элегантное решение:

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