your programing

구성으로 HashSet 값을 초기화하는 방법은 무엇입니까?

lovepro 2020. 9. 30. 11:12
반응형

구성으로 HashSet 값을 초기화하는 방법은 무엇입니까?


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"a"와 "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());

여기서 수집기는 set -> (Set<T>)Set.of(set.toArray())소스 코드 의 명령문 에서 분명한 것처럼 Java 9에 도입 된 수정 불가능한 집합을 실제로 반환합니다 .

한 가지 주목할 점 은 메서드 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에서 Stream 사용

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.unmodifiableSet () 사용

우리는 다음 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.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).


몇 가지 방법이 있습니다.

이중 중괄호 초기화

이것은 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 컬렉션 에는 특정 유형의 요소 Sets.newHashSet(T...)로을 채우는 메소드가 HashSet있습니다.


값이 하나만 있고 불변 세트 를 얻으려면 다음으로 충분합니다.

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

가장 편리한 방법 중 하나는 컬렉션과 varargs를받는 일반 Collections.addAll () 메서드를 사용하는 것입니다.

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

요소를 포함하는 불변의 Set을 얻게됩니다. 자세한 내용은 인터페이스 Set 의 Oracle 설명서 를 참조하십시오 .


새를 만들기위한 coobird 's answer의 유틸리티 함수 일반화 HashSet:

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

포함 된 Set 유형이 열거 형이면 자바 빌드 팩토리 메서드 (1.5 이후)가 있습니다.

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

함께 이클립스 컬렉션 초기화 할 수있는 몇 가지 방법이 있습니다 Set하나 개의 문장의 문자 'A'와 'B'를 포함하는가. Eclipse Collections에는 객체 및 기본 유형 모두에 대한 컨테이너가 있으므로 변경 가능, 불변, 동기화 및 수정 불가능 버전 둘 다에 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 Collections는 Java 5-8과 호환됩니다.

참고 : 저는 Eclipse Collections의 커미터입니다.


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

But in some cases, if we mentioned that is a good smell to make final collections unmutable, it could be really useful:

final Set<String> a = Collections.unmodifiableSet(new HashSet<String>(){{
    add("1");
    add("2");
}})

A bit convoluted but works from Java 5:

Set<String> h = new HashSet<String>(Arrays.asList(new String[] {  
    "a", "b"
}))

Use a helper method to make it readable:

Set<String> h = asSet ("a", "b");

public Set<String> asSet(String... values) {
    return new HashSet<String>(java.util.Arrays.asList(values));
}

Just a small note, regardless of which of the fine approaches mentioned here you end up with, if this is a default that usually goes unmodified (like a default setting in a library you are creating), it is a good idea to follow this pattern:

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

The benefit depends on the number of instances you create of that class and how likely it's that defaults will be changed.

If you decide to follow this pattern, then you also get to pick the method of set initialization that's most readable. As the micro differences in efficiency between the different methods will probably not matter much as you will be initializing the set only once.


Using Java 8 we can create HashSet as:

Stream.of("A", "B", "C", "D").collect(Collectors.toCollection(HashSet::new));

And if we want unmodifiable set we can create a utility method as :

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

This method can be used as :

 Stream.of("A", "B", "C", "D").collect(toImmutableSet(HashSet::new));

With the release of and the convenience factory methods this is possible in a cleaner way:

Set set = Set.of("a", "b", "c");

Can use static block for initialization:

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

This is an elegant solution:

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

The Builder pattern might be of use here. Today I had the same issue. where I needed Set mutating operations to return me a reference of the Set object, so I can pass it to super class constructor so that they too can continue adding to same set by in turn constructing a new StringSetBuilder off of the Set that the child class just built. The builder class I wrote looks like this (in my case it's a static inner class of an outer class, but it can be its own independent class as well):

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

Notice the addAll() and add() methods, which are Set returning counterparts of Set.add() and Set.addAll(). Finally notice the build() method, which returns a reference to the Set that the builder encapsulates. Below illustrates then how to use this Set builder:

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

Combining answer by Michael Berdyshev with Generics and using constructor with initialCapacity, comparing with Arrays.asList variant:

  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
  }
  • This is good if you pass a few values for init, for anything large use other methods
  • If you accidentally mix types with buildSetModif the resulting T will be ? extends Object, which is probably not what you want, this cannot happen with the buildSetModifTypeSafe variant, meaning that buildSetModifTypeSafe(1, 2, "a"); will not compile

참고URL : https://stackoverflow.com/questions/2041778/how-to-initialize-hashset-values-by-construction

반응형