티스토리 뷰

 

 

 

Set

Set인터페이스는 중복을 허용을 하지 않으면서 저장 순서가 유지되지 않는  컬렉션을 구현하는 데 사용됩니다.

셋 상속 구조

 

 

HashSet

 

Set인터페이스를 구현한 가장 대표적인 컬렉션이며, Set인터페이스의 특징대로 HashSet은 중복된 요소를 저장하지 않는다.

 

JAVA17 API : HashSet

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/HashSet.html

 

HashSet (Java SE 17 & JDK 17)

Type Parameters: E - the type of elements maintained by this set All Implemented Interfaces: Serializable, Cloneable, Iterable , Collection , Set Direct Known Subclasses: JobStateReasons, LinkedHashSet This class implements the Set interface, backed by a h

docs.oracle.com

 

선언방법

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

Set<?> set1 = new HashSet<>();
HashSet<?> set2 = new HashSet<>();

System.out.println(set1);
System.out.println(set2);
// 출력 : [] 
// 즉, 둘다 아무것도 없는 상태

 

주요 메서드

메서드 설 명
boolean addAll(Collection c) 주어진 컬렉션에 저장된 모든 객체들을 추가한다. (합집합)
boolean removeAll(Collection c) 주어진 컬렉션에 저장된 모든 객체와 동일한 것들을 HashSet에서 모두 삭제한다. (차집합)
boolean retainAll(Collection c) 주어진 컬렉션에 저장된 객체와 동일한 것만 남기고 삭제한다. (교집합)

 

 

Tip) 나머지 주요 메서드는  Java API 공식 문서에서 확인하면 좋습니다.

 

 

 

 

LinkedHashSet

 

중복을 허용하지 않으면서 순서를 유지하는 것이다.

List(컬렉션)에서도 LinkedList를 사용했었고 중간에 데이터를 추가, 삭제하는데 ArrayList보다 속도가 더 빨랐다.

그럼 LinkedHashSet도 데이터의 중간에 추가, 삭제하는데 HashSet보다 상대적으로 성능이 빠릅니다.

그래서 중간에 추가 및 삭제 작업을 빈번하게 발생하고 요소의 순서가 유지되어야 하는 경우에는 HashSet보다 LinkedHashSet을 사용하는 것이 성능이 좋습니다.

 

JAVA17 API : LinkedHashSet

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/LinkedHashSet.html

 

LinkedHashSet (Java SE 17 & JDK 17)

Type Parameters: E - the type of elements maintained by this set All Implemented Interfaces: Serializable, Cloneable, Iterable , Collection , Set Hash table and linked list implementation of the Set interface, with predictable iteration order. This impleme

docs.oracle.com

 

선언방법

import java,util.Set;
import java.util.HashSet;
import java.util.LinkedHashSet;

Set set1 = new LinkedHashSet();
HashSet set2 = new LinkedHashSet();
LinkedHashSet set3 = new LinkedHashSet();

 

 

 

 

TreeSet

 

이진 검색 트리라는 자료구조의 형태로 데이터를 정렬된 순서로 저장하고 중복된 요소를 허용하지 않는 컬렉션 클래스이다.

 

Java17 API : TreeSet

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/TreeSet.html

 

TreeSet (Java SE 17 & JDK 17)

Type Parameters: E - the type of elements maintained by this set All Implemented Interfaces: Serializable, Cloneable, Iterable , Collection , NavigableSet , Set , SortedSet A NavigableSet implementation based on a TreeMap. The elements are ordered using th

docs.oracle.com

 

선언방법

import java,util.Set;
import java.util.TreeSet;

Set<?> set1 = new TreeSet<>();
TreeSet<?> set2 = new TreeSet<>();

System.out.println(set1);
System.out.println(set2);
// 출력 : [] 
// 즉, 둘다 아무것도 없는 상태

 

주요 메서드

메서드 설 명
Object ceiling(Object o) 지정된 객체와 같은 객체를 반환한다. 없으면 큰 값을 가진 객체 중 제일 가까운 값의 객체를 반환한다. 또 없으면 null을 반환한다.
NavigableSet descendingSet() TreeSet에 저장된 요소들을 역순으로 정렬해서 반환한다.
Object floor(Object o) 지정된 객체와 같은 객체를 반환한다. 없으면 작은 값을 가진 객체 중 제일 가까운 값의 객체를 반환한다. 또 없으면 null을 반환한다.
SortedSet headSet(Object toElement) 지정된 객체보다 작은 값의 객체들을 반환한다.
매개 변수 2번째 자리에 true이면, 같은 값의 객체도 포함된다.
Object higher(Object o) 지정된 객체보다 큰 값을 가진 객체 중 제일 가까운 값의 객체를 반환한다. 없으면 null을 반환한다.
SortedSet subSet(Object fromE, Object toE) 범위 검색(fromE와 toE)의 결과를 반환한다. (끝 범위인 toE는 포함하지는 않는다.)
SortedSet tailSet(Object fromE) 지정된 객체보다 큰 값의 객체들을 반환한다.

 

 

궁금했던 점

Set은 많이 사용해 봤지만 TreeSet은 어디서 사용하고 어떻게 사용하는지 너무 궁금했다.

 

  1. 사용자의 이름이나 나이 등의 데이터를 정렬하여 저장하고 접근해야 할 때
  2. 특정 날짜 범위 내의 이벤트를 저장하고, 특정 기간 내의 이벤트를 조회할 때

 

그러면?? TreeSet에 데이터를 넣으면 어떻게 출력이 될까?

import java.util.TreeSet;

public class TreeSetGo {
    public static void main(String[] args) {
        // TreeSet 생성
        TreeSet<Integer> numbers = new TreeSet<>();

        // 요소 추가
        numbers.add(5);
        numbers.add(3);
        numbers.add(8);
        numbers.add(1);

        // 정렬된 순서로 요소 출력
        for (int number : numbers) {
            System.out.println(number);
        }
    }
}
// 출력은 1, 3, 5, 8 순으로 줄바꿈되며 출력된다!

 

 

 

 

Equals() 와 HashCode() 오버라이딩 해야 하는 이유

 

원인) 오버라이딩 안 했을 경우

코드로 알아보도록 하자. 우선 사람 클래스가 있다고 하겠다.

class Person{
	String name;
	int age;
    
	Person(){}
	Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
    
	public String toString() {
		return name + " : " + age;
	}
}

이제 실행을 해보자.

import java.util.*;

public class Main {
	public static void main(String[] args) {
		
		HashSet set = new HashSet();
		
		set.add("abe");
		set.add(new Person("유재석", 50));
		set.add(new Person("유재석", 50));
		
		System.out.println(set);
	}
}

 

이렇게 실행하면 뭐가 나올지 생각이 나나?

Set은 중복을 제거해 주니까 Person클래스로 생성한 저 인스턴스는 같을 거니 1개는 제거가 될 것이라고 생각된다.

그럼 [abc, 유재석 : 50]이 되어야 할 것이다.

 

 

정준화 당황
출처 : 무한도전

 

 

하지만 실행해서 console창에 보면 결과는 아주 다르게 나온다.  [abe, 유재석 : 50, 유재석 : 50] 이게 나오게 되는 것이었다.

 

 

 

결과) 오버라이딩 했을 경우

equals() 를 이용한 비교에 의해서 true를 얻은 두 객체에 대해 각각 hashCode()를 호출해서 얻은 결과는 반드시 같아야 한다.

하지만 hashCode()가 같다고 해서 equals가 항상 true인 것은 아니다.

class Person{
	String name;
	int age;
    
	Person(){}
	Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
    
	@Override
	public int hashCode() {
		return Objects.hash(age,name);
	}
    
	@Override
	public boolean equals(Object obj) {
		if(obj instanceof Person) {
			Person tem = (Person)obj;
			return name.equals(tem.name) && age == tem.age;
		}
        
		return false;
	}
    
	public String toString() {
		return name + " : " + age;
	}
}

이제 실행을 다시 해보자.

import java.util.*;

public class Main {
	public static void main(String[] args) {
		
		HashSet set = new HashSet();
		
		set.add("abe");
		set.add(new Person("유재석", 50));
		set.add(new Person("유재석", 50));
		
		System.out.println(set);
	}
}

객체를 완전히 같게 만들어 주었더니  [유재석 : 50, abc] 이나오는 것이다.

이러한 이유로 객체를 동일, 동등하게 만들기 위해 equals(), hashCode()를 오버라이딩 하는 것이다.

 

 

박명수

 

 

Iterator 반복자 이용하는방법

 

Tip) iterator() 메소드는 List와 Set 계열에서만 사용가능하다.

 

 

만약 Map의 경우 Set 또는 List화 시켜서 iterator()를 사용해야한다. (Map 계열에서는 사용 불가)

HashSet<Student> hs = new HashSet<Student>();
hs.add(new Student("이순신", 26, 100));
hs.add(new Student("유재석", 21, 80));
hs.add(new Student("송지효", 23, 60));

Iterator<Student> it = hs.iterator();

while(it.hasNext()) {	// it에 next로 빼올 값이 남아 있으면 true / 없으면 false
	System.out.println(it.next());	// StringTokenizer와 같은 원리
}

// 출력 
// Student [name=이순신, age=26, score=100]
// Student [name=유재석, age=21, score=80]
// Student [name=송지효, age=23, score=60]

 

 

 

 

감사합니다.

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함