2월 12, 2024

[HashSet] 자바 HashSet 개념 및 활용법!

자바에 존재하는 독특한 HashSet에 대해서 알아보도록 하자.

HashSet의 가장 큰 특징은 중복을 걸러낸다는 것이다!! 따라서 Java에서 무언가를 중복없이 저장해놓고 싶을때 사용하면 좋은 class이다. 


(1) HashSet이란? 

그럼 정확히 HashSet은 자바에서 어떤 위치에 있을까? HashSet은 자바의 Set 인터페이스를 구현한 클래스이다. Set 인터페이스를 구현한 클래스에는 HashSet이외에도 TreeSet이 존재한다. 다른 점을 꼽자면 HashSet은 자동으로 정렬이 되지 않는 반면, TreeSet은 자동으로 정렬이 된다는 점이다. 


(2) HashSet은 언제사용하면 좋을까? 


중복을 허락하지 않고 정렬이 필요 없는 경우에 HashSet을 사용해주면 된다.

Set의 경우 '순서'가 없기 때문에 index가 있을 수 없다. 따라서 특정 index에 있는 무언가를 가져오고 싶을때는 HashSet을 쓸 수 없다! 


또한 값을 추가하거나 삭제하는 것이 많은 알고리즘을 구현할 때 HashSet의 사용은 피하는 것이 좋다. 왜냐하면 값 추가/삭제에 시간이 오래 소요되기 때문이다. 이는 HashSet이라는 것은 위에서도 언급했지만 index 라는 개념 자체가 없기 때문에 해당 값이 HashSet안에 존재하는지/존재하지 않는지의 여부를 살펴보고 존재하지 않으면 추가를 하는 식이기 때문이다. 삭제도 마찬가지이다. 물론 중복없는 값을 추가할 때는 자주 사용되고 매우 유용하긴 하지만 List 구조에 비해서 속도가 느린 것은 사실이다. 


(3) HashSet 작동원리

그렇다면 HashSet은 어떻게 중복없이 Set을 만드는 것일까? 그 과정을 간단히 설명해보겠다.

  • 1. 저장하려는 객체의 hashCode()를 호출한다. 
  • 2. 이미 저장되어 있는 객체중에서 같은 hashCode()가 있는지 판단한다.
  • 3. 위의 과정에서 같은 hashCode()의 객체가 있다면 equals() 메서드로 두 객체의 동일성 여부를 판단한다.
  • 4. 만약 equals() 메서드의 반환값이 true라면 같은 객체라고 판단하여 중복해서 저장하지 않는다.
  • 5. 만약 위의 과정을 거쳐 저장되어 있는 객체 중 같은 객체라고 판단되는 객체가 없다면 저장해준다.


(4) HashSet 사용법


1. HashSet 선언하기

HashSet<Integer> hs=new HashSet<>();

가장 일반적으로 HashSet을 선언하는 방법이다. HashSet에 담을 객체에 따라서 < > 안에 사용하는 코드를 바꾸어주면 된다. 대부분 정수를 저장하므로 이 경우에는 Integer를 넣어주면된다. 만약 문자 한글자를 넣어주고 싶다면 Character를 적어주면 된다.


HashSet<Integer> hs=new HashSet<Integer>(20);

위의 코드와 같이 써주면 초기 HashSet을 만들어줄 때 초반의 용량 (capacity)를 20개로 하겠다는 것이다. 만약에 용량을 지정해주지 않는다면 default 값으로는 16이 들어간다. 물론 용량을 지정해주지 않아도 16개가 넘어가면 HashSet은 자연스럽게 용량을 늘려준다. 하지만 이 과정에서 원치 않는 범위까지(2배) 용량을 늘려주기 때문에 만약 내가 원하는 용량을 알고 있다면 초반에 선언할 때 함께 적어주는 것이 좋다. 



2. 추가 


HashSet을 선언해주었으면 다음으로는 값을 추가하는 것을 살펴보자. 이는 간단하게 add를 사용해주면 된다. 

hs.add(1);

위의 코드와 같이 말이다. 



3. 특정 값을 삭제하기


HashSet은 index가 없기 때문에 index에 있는 값을 지운다라는 개념이 성립하지 않는다. 따라서 해당 값을 지워주는 것이다. 만약 내가 1이라는 값을 지워주고 싶다면 아래와 같이 코드를 작성해주면 된다.


hs.remove(1);


4. 특정 값이 있는지 없는지 살펴보기


HashSet에서 저장되어 있는 것 중 만약 특정 값이 있는지의 여부를 알고 싶다면 contains를 사용해주면 된다. 만약 1이 있는지 없는지를 알고 싶다면,

hs.contains(1);

을 사용해주면 되고 반환값은 true/false이기 때문에 조건문과 함께 활용하면 좋다. 



5. HashSet에 있는 값을 출력해보기

 

우리가 보통 배열의 경우에는 값을 출력하기 위해서 for문을 쓰는데 HashSet은 index가 없기 때문에 iterator를 사용해주어야 한다.

즉,

HashSet<Integer> hs=new HashSet<>();
hs.add(1);
hs.add(2);
hs.add(3); //값을 추가

Iterator it=hs.iterator();
while(it.hasNext()){ //다음것이 있는지 확인
System.out.println(it.next());  //있다면 출력
}

위와 같이 적어주면 된다. 



6. HashSet의 크기 

크기를 구하기 위해서는 size()라는 메서드를 사용해주면 된다.

int n=hs.size();

라고 써주면 된다. 



7. HashSet 전체 값 다 제거/ 초기화

HashSet에 저장되어 있는 모든 값을 제거하고 초기화하기 위해서는 clear() 를 사용해주면 된다.

hs.clear();

라고 쓰면 모든 값이 다 제거된다.