본문 바로가기
Backend/Java

Java 기초 문법 : 컬렉션(collection) - Set (2)

by 코딩쥐 2024. 10. 10.

Java에서 컬렉션이란 데이터의 집합을 의미한다. Collection 인터페이스는 모든 컬렉션의 최상위 인터페이스로 List, Set, Queue 등의 공통 기능을 정의한다. Map의 경우 구조상의 차이로 별도의 인터페이스로 정의되지만 Collection으로 분류된다.  모든 Collection은 저장될 객체의 타입을 지정할 수 있는 제네릭(Generic)타입을 지원한다.

 

  • Set : 순서가 없는 데이터의 집합으로 데이터의 중복을 허용하지 않는다.
    • 구현클래스 : HashSet, TreeSet
  • List : 순서가 있으며(인덱스 존재) 데이터의 중복을 허용한다. 
    • 구현클래스 : LinkedList, Vector, ArrayList
  • Queue : 순서가 있으며 요소는 큐의 앞쪽에서 제거되고, 새로운 요소는 뒤쪽에 추가된다.
    • 구현클래스 : LinkedList, PriorityQueue
  • Map : 키-값 쌍으로 데이터를 저장하며, 키는 중복을 허용하지 않는다. 키를 통해 매핑된 값을 가져올 수 있다.
    • 구현클래스 : HashMap, TreeMap

 

Set

순서가 없는 데이터의 집합으로 데이터의 중복을 허용하지 않는다. List를 사용하기 위해서는 List를 상속하고 있는 클래스의 인스턴스를 생성하여 사용해야한다. 가장 많이 사용되는 클래스의 경우 HashSet과 TreeSet이 있다. 

메서드 설명
.add() 요소를 추가한다. 이미 존재하는 경우 false를 반환한다.
.remove() 요소를 제거한다. 요소가 존재하면 true / 존재하지 않으면 false를 반환한다.
.contains() 요소가 Set에 포함되어있는지 확인한다. 포함되어 있으면 true/ 아니면 false를 반환한다.
.size() 요소의 개수를 반환한다.
.isEmpty() Set이 비어있는지 확인한다. 비어있으면 true/ 아니면 false를 반환한다.
.clear() Set의 모든 요소를 제거한다.
.iterator() Set의 요소를 반복할 수 있는 iterator로 반환한다.
.addAll() 지정된 컬렉션의 모든 요소를 Set에 추가한다. 중복된 요소는 추가되지 않는다.
.removeAll() 지정된 컬렉션에 포함된 모든 요소를 Set에서 제거한다.
.retainAll() 지정된 컬렉션에 포함된 요소만 남기고 나머지 요소를 제거한다. 

 

HashSet

Set인퍼테이스를 구현한 가장 대표적인 컬렉션으로 중복된 요소를 저장하지 않는다. 새로운 요소를 추가할 때 중복된 데이터가 저장될 경우 메서드가 false를 반환하고 데이터를 추가하지 않게 된다. 저장 순서를 유지하고자 하면 LinkedHashSet을 사용한다. 

package com.example;

import java.util.HashSet;
import java.util.Set;

public class Example01{
    public static void main(String[] args) {
        Set<String> hash1 = new HashSet<>();
        hash1.add("코딩쥐");
        hash1.add("티스토리");
        // HashSet의 경우 저장 순서가 무작위로 설정된다.
        System.out.println(hash1); // [티스토리, 코딩쥐]

        hash1.remove("티스토리");
        System.out.println(hash1); // [코딩쥐]

        System.out.println(hash1.contains("코딩쥐")); // true

        System.out.println(hash1.add("코딩쥐")); //false
        System.out.println(hash1.add("티스토리")); // true
        // 중복된 요소는 false를 반환하고, 저장이 되지 않는다.
        System.out.println(hash1); // [티스토리, 코딩쥐]
    }
}

 

컬렉션 병합

  • .addAll() : 지정된 컬렉션의 모든 요소를 해당 컬렉션에 병합한다. 중복된 요소는 추가되지 않는다.
  • .removeAll() : 지정된 컬렉션에 포함된 모든 요소를 해당 컬렉션에서 제거한다.
  • .retainAll() : 지정된 컬렉션에 포함된 모든 요소만 해당 컬렉션에 남기고, 나머지 요소는 제거한다.
package com.example;

import java.util.HashSet;
import java.util.Set;

public class Example01{
    public static void main(String[] args) {
        Set<String> greeting1 = new HashSet<>();
        greeting1.add("안녕");
        greeting1.add("Hello");
        greeting1.add("Hola");

        Set<String> greeting2 = new HashSet<>();
        greeting2.add("Xin chào");
        greeting2.add("Ciao");
        greeting2.add("안녕");

        Set<String> greeting3 = new HashSet<>();
        greeting3.add("Hola");
        greeting3.add("Ciao");

        // 컬렉션 병합, 중복된 요소는 추가되지 않는다.
        greeting1.addAll(greeting2);
        System.out.println(greeting1); // [Hello, Ciao, 안녕, Xin chào, Hola]

        // Hola, Ciao 항목이 제거된 모습을 볼 수 있다.
        greeting1.removeAll(greeting3);
        System.out.println(greeting1); // [Hello, 안녕, Xin chào]

        // [Hello, 안녕, Xin chào] 중에서 greeting2에 포함된 요소들만 남았다.
        greeting1.retainAll(greeting2);
        System.out.println(greeting1); //[안녕, Xin chào]
    }
}

 

TreeSet

HashSet의 경우에는 요소의 해시 코드를 이용해서 데이터를 저장하다보니 요소의 저장 순서가 유지 되지 않는다. TreeSet은 이진 탐색 트리를 기반으로 하여 요소를 정렬된 상태로 유지한다. HashSet의 경우 빠른 검색을 위해서 유용하고, TreeSet의 경우 범위 검색이나 정렬된 순서가 필요할 때 유용하다.

* 이진 탐색 트리 : 추가되는 노드의 값이 현재 노드의 값보다 작으면 왼쪽 서브트리, 크면 오른쪽 서브트리에 이동하면서 적절한 위치에 데이터가 삽입된다. 

메서드 설명
.first() 첫번째 요소를 반환한다.
.last()  마지막 요소를 반환한다.
.higher() 지정한 값보다 큰 값을 가진 요소 중 제일 가까운 값의 요소를 반환한다.
.lower() 지정한 값보다 작은 값을 가진 요소 중 제일 가까운 값의 요소를 반환한다.
.ceiling() 지정한 값 이상의 요소 중 가장 작은 요소를 반환한다.
.floor() 지정한 값 이하의 요소 중 가장 큰 요소를 반환한다.
.subSet(a, b) a 이상 b 미만의 검색 결과를 반환한다.
.headSet() 주어진 값보다 작은 요소들을 반환한다. ( 값 미만 ) 
.tailSet() 주어진 값보다 큰 요소들을 반환한다.  ( 값 이상 )
package com.example;

import java.util.TreeSet;

public class Example01{
    public static void main(String[] args) {
        //TreeSet의 메서드 참조를 위해 TreeSet타입으로 참조
        TreeSet<Integer> treeset = new TreeSet<>();
        treeset.add(1);
        treeset.add(37);
        treeset.add(9);
        treeset.add(29);
        treeset.add(51);
        treeset.add(13);
        // TreeSet은 정렬된 순서를 갖는다.
        System.out.println(treeset); // [1, 9, 13, 29, 37, 51]
        System.out.println(treeset.first()); // 1
        System.out.println(treeset.last()); // 51
        System.out.println(treeset.higher(37)); // 51 - 해당 값 초과
        System.out.println(treeset.lower(29)); // 13 - 해당 값 미만
        System.out.println(treeset.ceiling(37)); // 37 - 해당 값 이상
        System.out.println(treeset.floor(29)); // 29 - 해당 값 이하
        System.out.println(treeset.subSet(9, 51)); // [9, 13, 29, 37] - 첫번째 값 이상, 두번째 값 미만
        System.out.println(treeset.headSet(29)); // [1, 9, 13] - 해당 값 미만
        System.out.println(treeset.tailSet(37)); // [37, 51] - 해당 값 이상

    }
}