개발/Java

[Java] Collection Framework - Set

suniverse 2023. 3. 4. 23:31

- 컴퓨터 시스템에서 데이터를 효율적으로 저장 및 관리하는 방법(자료구조론)

=> 자바에서 자료구조를 구현하여 제공하는 클래스들의 모음이다. 

=> 기타 대부분의 언어들은 자료구조를 개발자가 직접 구현해야 하지만 

자바는 클래스 내의 메서드를 통해 자료구조를 활용할 수 있도록 지원해준다. 

- java.util 패키지에 클래스 및 인터페이스로 지공된다. 

 

🔍 컬렌션 3대 인터페이스 

Set, List, Map

=> 각 인터페이스를 구현한 구현체 클래스들이 제공된다. 

=> 이 중, Set과 List 계열은 Collection 인터페이스를 공통으로 상속받았기 때문에 대부분의 메서드가 동일하다. 

 


1. Set 계열 

- 저장 순서가 유지되지 않는다 => 즉, 인덱스 사용이 불가능 하다 

- 데이터 중복을 허용하지 않는다. 중복데이터는 애초에 저장되지 않는다. 

그래서 아주 효율적인 중복제거 수단으로 사용된다. 

- Set 계열의 구현체 클래스 : HashSet, TreeSet 등 

 

✍ HashSet 객체 생성하기 

public static void main(String[] args) {
    Set set = new HashSet(); // HashSet 객체 생성 

    System.out.println("Set 객체가 비어있는가? : " + set.isEmpty());
    System.out.println("Set 객체에 저장된 요소 갯수 : " + set.size());
    System.out.println("Set 객체의 모든 요소 : " + set.toString());
    System.out.println("Set 객체의 모든 요소 : " + set); // toString() 생략 가능 
}

원래는 HashSet set = new HashSet();의 형태지만 

위의 코드는 HashSet을 Set으로 업태스팅하여 작성하였다. 

대부분의 메서드를 부모 인터페이스인 Set 인터페이스가 보유중이므로 

업캐스팅 상태에서도 대부분의 기능을 사용하는 데 문제가 없기 때문이다. 

 

isEmpty() 메서드는 객체의 데이터 유무를 판단하여 리턴해주고 

set.size() 메서드는 배열의 length와 유사하다. 컬렉션의 크기를 리턴해준다 

객체의 모든 요소를 출력하기 위해서는 참조변수 그 자체를 그냥 출력하거나 toString()을 붙여주면 된다. 

 

✍ Set 객체에 데이터 추가하기 

set.add(1);
set.add(100);
set.add("abcde");
set.add(3.14);
set.add('A');
System.out.println("Set 객체의 모든 요소 : " + set);

=> set.add() 를 통해 데이터를 추가 할 수 있다. 단, 저장 순서가 유지 되지 않기 때문에 순서는 달라진다 

데이터 타입 종류와 상관없이 모든 데이터들을 입력할 수 있다. 

 

💻

 

✍ Set 객체에 저장된 요소 확인하기 

System.out.println(set.contains(1));

contains() 메서드를 통해 set에 저장된 요소의 존재 유뮤를 리턴받을 수 있다. 

 

💻

1은 저장되어 있기 때문에 true가 리턴된다. 

 

✍ 객체에 저장된 요소 삭제하기 

set.remove(1);
System.out.println(set);

remove() 메서드를 통해 요소를 삭제할 수 있다. 삭제한 후 모든 요소를 출력해보면 

💻

1이 삭제된 걸 확인할 수 있다. 

 

✍ addAll() 

새로운 set 인스턴스를 생성한 후 기존에 저장되어 있던 데이터를 전부 추가할 수 있다. 

public static void main(String[] args) {
    Set set = new HashSet(); // HashSet 객체 생성 
    
    set.add(1);
    set.add(100);
    set.add("abcde");
    set.add(3.14);
    set.add('A');

    Set set2 = new HashSet(); // set2 인스턴스 생성
    set2.addAll(set); // set의 모든 요소를 set2에 추가 
    System.out.println(set2); // set2의 모든 요소 출력 

}

=> set2 인스턴스를 생성한 후 

이미 set.add()를 통해 추가되어 있던 set의 모든 요소를 그대로 set2에 저장할 수 있다. 

addAll()이후 set2의 모든 요소를 출력해보면 

 

💻

set의 모든 요소가 set2에 저장된 걸 확인 할 수 있다. 

 

✍ 저장된 요소 모두 제거하기 

set2.clear();
System.out.println(set2);

clear() 메서드를 통해 저장된 요소를 모두 제거할 수 있다. 

 

💻

=> 요소가 모두 제거된 걸 확인할 수 있다 

 

주의!!!!!!!!!!!!!!!!!!!!!!!! 

HastSet등 컬렉션 객체 생성 시 파라미터로 다른 컬렉션 객체를 전달하면

해당 컬렉션 객체의 요소를 갖는 새로운 컬렉션 객체가 생성된다. 

Set set3 = new HashSet(set); // set3 객체 생성 
System.out.println("set3의 모든 요소 : " + set3);
System.out.println("set의 모든 요소 : " + set);

여기서 주의할 점은 !

데이터가 저장된 주소를 공유하는 것이 아닌 실제 요소를 복사하여 전달하므로 

저장된 요소는 갖지만 주소를 다르게 생성된다. 

 

Set set3 = new HashSet(set);
System.out.println("set3의 모든 요소 : " + set3);
System.out.println("set의 모든 요소 : " + set);

System.out.println("set과 set3객체는 동일한 객체인가? : " + (set==set3));
System.out.println(set.equals(set3));

 

💻

set3 인스턴스를 생성할 때 파라미터로 set을 전달하여 set의 요소가 모두 복사되었다. 

요소는 동일하지만 다른 주소값을 가진 객체이다. 

 

🔍 TreeSet 객체 활용하기 

TreeSet 객체를 활용하면 같은 타입 데이터가 저장된 Set 객체 정렬이 가능하다.

주의! 반드시 같은 타입 데이터만 저장해야한다! 

=> 이진 탐색 트리 (Binary Search Tree)를 개량한 레드-블랙(Red-Black Tree) 구조 사용 

수치데이터는 수치의 크기순으로 오름차순 정렬되며 ( 0 -> 9 ) 

문자데이터는 문자 코드값의 크기 순으로 오름차순 정렬되므로 

수치 데이터와 문제 데이터의 정렬 결과는 다를 수 있다 ! 

 

Set set4 = new HashSet(); // set4 객체 생성 

// 요소 추가 
set4.add(100);
set4.add(99);
set4.add(500);
set4.add(2);
set4.add(35);
set4.add(999);

System.out.println(set4); // 요소 출력 

Set<Integer> set5 = new TreeSet(set4); // set4 요소를 set5에 추가 => TreeSet 자동 정렬 

System.out.println(set5); // 요소 출력

set4에 저장한 요소들을 set5 TreeSet으로 정렬 한다 

 

💻

set4와 set5의 차이를 확인할 수 있다. set5는 TreeSet 객체를 활용하였으므로 요소들이 정렬되어 출력되었다. 

 

✍ Set 계열의 모든 요소를 반복문을 통해 출력하기 

for(int i : set5) {
    System.out.println(i);
}

향상된 for문으로 set 객체의 요소를 출력할 수 있다. 

 

💻