Set 인터페이스는 HashSet, LinkedHashSet, TreeSet 클래스로 구현할 수 있다.
List와 달리 Set은 중복을 허용하지않고 순서를 유지하지 않는다.
import java.util.HashSet;
Set<String> set = new HashSet<String>();
set.add("홍길동");
set.add("김철수");
set.add("이영희");
set.add("김철수");
System.out.println(set.toString()); //=System.out.println(set);
System.out.println("총 인원수 : " + set.size()); //3
set은 HashSet이라는 컬렉션 객체를 참조하는 변수이다.
set 안에는 요소들이 저장되어 있고, set을 출력하면 컬렉션에 저장된 요소들이 출력된다.
ArrayList와는 달리 홍길동, 김철수, 이영희 순으로 넣어도 결과는 무작위로 나온다.(순서없음)
그리고 중복을 허용하지 않기 때문에 "김철수"를 두번넣어도 set.size()가 3이다.
toString()은 해당 컬렉션 객체의 문자열 표현을 반환해준다.
자바에서는 기본적으로 모든 객체가 toString()메서드를 가지고 있다.(Object클래스의 메서드)
1. HashSet클래스
1) add() : 객체 저장
객체가 저장된다면 true, 중복 객체면 false를 리턴한다.
그래서 중복된 값을 넣어도 에러는 나지 않지만 값이 들어가지는 않는다.
예를 들어 3명의 이름을 set에 넣은 뒤
Set<String> set = new HashSet<String>();
set.add("홍길동");
set.add("김철수");
set.add("이영희");
System.out.println(set.toString()); //[홍길동, 이영희, 김철수]
"김철수"를 다시 add()하면 set에는 들어가지 않는다. 콘솔에 false가 찍히는 것도 볼 수 있다.
set에 없는 "황찬우"를 add()하면 set에 들어간다.(순서X). 콘솔에 true가 찍힌다.
System.out.println(set.add("김철수")); //false
System.out.println(set.add("황찬우")); //true
System.out.println(set); //[황찬우, 홍길동, 이영희, 김철수]
ArrayList에서의 add()는 반환값이 void이지만 HashSet에선 boolean을 리턴.
2) contains() : 특정 객체가 저장되어있는지 확인
System.out.println(set.contains("황찬우")); //true
3) isEmpty() : 컬렉션이 비어있는지 확인
System.out.println(set.isEmpty()); //false
4) remove() : 주어진 객체 삭제. HashSet은 index가 없으므로 직접 지정해줘야한다.
5) clear() : 전부 삭제
6) size() : 저장되어 있는 전체 객체 수
7) get() : Set에서는 사용할 수 없다. 순서(index)가 없으므로..
getClass()밖에 안뜬다.
8) iterator() : 저장된 객체를 한번씩 가져오는 반복자를 리턴.
반복자는 chatGPT형님께서 설명..
HashSet의 값들을 출력하고 싶을 때는 어떻게 해야할까?
ArrayList에선 get()메서드를 이용해 for문으로 출력했지만 HashSet은 get()을 사용할 수 없다.
두가지 방법이 있다.
1. 반복자(iterator)
Set<String> set = new HashSet<String>();
Iterator<String> iter = set.iterator();
Set의 iterator() 메서드를 호출하여 Iterator<String> 타입의 반복자 iter를 얻는다.
iter는 Set에 저장된 요소를 순회할 때 사용할 수 있다.
8-1) hasNext(): 다음 요소가 있는지를 확인. => 조건으로 이용 가능
8-2) next(): 다음 요소를 가져오는 역할 => 반복문으로 이용 가능
while(iter.hasNext()) { //자료가 있으면 true 하나씩 끄집어냄
String name = iter.next();
System.out.println("이름 : " + name);
}
현재 set에서 "김철수"를 삭제하고, 삭제한 후의 set을 조회해보자.
for(String name:set) {
System.out.println("이름 : " + name);
}
set.remove("김철수"); //직접 지정해서 삭제.
System.out.println("**제거 후 출력**");
Iterator<String> iter = set.iterator();
while(iter.hasNext()) { //자료가 있으면 true 하나씩 끄집어냄
String name = iter.next();
System.out.println("이름 : " + name);
}
결과
iterator()를 이용한 이유는 get(index) 메서드를 쓸 수 없어서이다.
하지만 사실 향상된 for문으로 name에 set의 값을 쉽게 넣을 수 있다.
for(String name:set) {
System.out.println("이름 : " + name);
}
set.remove("김철수"); //순서가 없어서 직접 지정해서 삭제
System.out.println("**제거 후 출력**");
/*
Iterator<String> iter = set.iterator();
while(iter.hasNext()) { //자료가 있으면 true 하나씩 끄집어냄
String name = iter.next();
System.out.println("이름 : " + name);
}
*/
//iterator()쓴거랑 향상된 for문이랑 결과 같음.
for(String name:set) {
System.out.println("이름 : " + name);
}
결과
(향상된 for문)
향상된for문이 iterator()로 하는 것보다 훨씬 간단하게 set을 조회할 수 있는걸 알 수 있다.
하지만 반복자를 명시적으로 사용하는 경우에는 요소를 추가하거나 삭제할 때 유용하며,
일부 상황에서는 향상된 for문을 사용하는 것보다 더 유연하게 요소를 조작할 수 있다고 한다..