Java_Collection Framework, Iterator
Collection Framwork
- 자바가 자료구조를 구현해 놓은 것
- 자료구조 - 객체의 저장, 삭제, 조회 등의 기능을 제공하는 것
- 자바의 모든 자료구조 구현 클래스는 Collection 인터페이스를 구현한 클래스
- Collection 인터페이스에 정의된 모든 기능을 구현하고 있다
자바 자료구조 특징
- 객체만 저장할 수 있다
- 크기가 가변적이다
- 다양한 메소드를 지원
배열과 Collection의 비교
구분 | 배열 | 콜렉션 |
데이터 | 기본자료형, 객체 | 객체 |
길이 | 불변 | 가변 |
저장 | 인덱스필요 | 맨 마지막요소의 끝에 자동으로 저장 |
삭제 | 인덱스필요 | 삭제 후 다음요소로 |
삭제 후 | 해당부분 데이터가 비어있음 | 자동으로 채워짐 |
Enhanced - for ( 향상된 for문) | 배열의 끝까지 반복 | 요소가 있는 부분까지만 반복 |
Collection<E>
- 모든 자료구조 클래스의 최상위 인터페이스
주요 메소드
메소드 종류 | 메소드 수행 내용 |
boolean add(E e) | 자료구조에 새로운 요소를 추가 |
boolean addAll(Collection<? extends E> c) | 자료구조에 다른 자료구조의 모든 요소를 추가 |
void clear( ) | 자료구조의 모든 요소를 삭제 |
boolean contains(Object e) | 자료구조에 지정된 객체가 존재하는지 조회 |
boolean isEmpty( ) | 자료구조가 비어있는지 확인 |
Iterator<E> iterator( ) | 자료구조의 각 요소를 반복해서 추출해주는 반복자객체를 반환 |
boolean remove(Object e) | 자료구조에서 지정된 객체를 삭제 |
int size( ) | 자료구조에 저장된 요소의 갯수를 반환 |
Object[ ] toArray( ) | 자료구조에 저장된 요소를 배열로 반환 |
Collection의 주요 하위 인터페이스
Set<E>
- 중복을 허용하지 않는다 ( 동일한 객체를 2개 저장할 수 없다)
주요 구현 클래스
HashSet<E> : 가장 많이 사용하는 Set 구현 클래스
객체의 동일성 비교를 구현하기 위해서 equals( ), hashcode( ) 메소드를 재정의할 필요가 있다( HashSet<E>에 저장되는 객체가 구현해야 한다 )
String, Wrapper 클래스는 equals( )와 hashcode( )가 이미 재정의 되어 있다
HashSet<E> 사용예제
public static void main(String[] args) {
// String 객체를 저장하는 HashSet 객체 생성하기
HashSet<String> set = new HashSet<String>();
// boolean add(E e) 메소드를 사용해서 HashSet 객체에 String 객체 저장하기
set.add("홍길동");
set.add("고길동");
set.add("길동");
set.add("노길동");
set.add("신길동");
set.add("주길동");
set.add("말동");
// 중복으로 인해서 저장되지 않음
set.add("말동");
set.add("말동");
set.add("말동");
// int size() 메소드를 사용해서 HashSet 객체에 저장된 객체의 갯수 조회하기
int size = set.size();
System.out.println("저장된 객체의 갯수: "+size);
// 향상된 for문을 사용해서 HashSet객체에 저장된 객체들을 하나씩 처리하기
// HashSet은 index가 없다. 일반 for문으로는 HashSet 객체에 저장된 값들을 처리할 수 없다
System.out.println("향상된 for문으로 HashSet 객체에 저장된 객체 처리");
for(String s : set) {
System.out.println(s);
}
System.out.println();
// Stream을 사용해서 HashSet 객체에 저장된 객체들을 하나씩 처리하기
System.out.println("Stream을 사용해서 HashSet 객체에 저장된 객체 처리");
Stream<String> stream = set.stream();
stream.forEach((String s)-> System.out.println(s));
// boolean contains(Object o)를 사용해서 객체의 저장여부를 조회하기
boolean isExist = set.contains("고길동");
System.out.println("존재여부: "+isExist);
// boolean isEmpty()를 사용해서 HashSet 객체가 비어있는지 조회하기
boolean isEmpty = set.isEmpty();
System.out.println("비어있는지 확인: "+isEmpty);
// void clear() HashSet 객체에 저장된 모든 객체 삭제하기
set.clear();
System.out.println("비어있는지 확인: "+set.isEmpty());
}
HashSet<E> equals( ), hashCode( ) 사용예제
public static void main(String[] args) {
HashSet<User> set = new HashSet<>();
set.add(new User("go", "고길동"));
set.add(new User("no", "노길동"));
set.add(new User("park", "박길동"));
set.add(new User("kim", "김길동"));
set.add(new User("Oh", "오길동"));
set.add(new User("shin", "신길동"));
set.add(new User("nu", "누길동"));
set.add(new User("nu", "누길동"));
set.add(new User("nu", "누길동"));
for(User u : set) {
System.out.println(u.id +", " +u.name);
}
}
static class User {
String id;
String name;
public User(String id, String name) {
this.id = id;
this.name = name;
}
/*
* hashCode()와 equals()메소드를 재정의해서
* id값이 같은 User객체는 같은 객체로 판단하도록 하였음
*/
@Override
public int hashCode() {
return Objects.hash(id);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
return Objects.equals(id, other.id) && Objects.equals(name, other.name);
}
}
TreeSet<E> : 저장되는 요소가 오름차순으로 정렬되어서 저장
TreeSet에 저장하는 객체는 반드시 Comparable<E>를 인터페이스로 구현해야 한다.
String, Wrapper 클래스는 Comparable를 인터페이스를 구현하고 있다
TreeSet<E> 사용예제
public static void main(String[] args) {
TreeSet<String> set = new TreeSet<String>();
set.add("고길동");
set.add("너길동");
set.add("노길동");
set.add("하길동");
set.add("정길동");
set.add("박길동");
for(String s : set) {
System.out.println(s);
}
}
/* 결과는
* 고길동
* 너길동
* 노길동
* 박길동
* 정길동
* 하길동
*/
TreeSet<E> 사용예제
// 로또번호 추출하는 예제
public static void main(String[] args) {
/*
* 로또번호 추출하기
* - TreeSet<E> 사용
* 1. 중복된 값을 저장하지 않는다
* 2. 값이 오름차순으로 정렬되어 저장된다
*
*/
Random random = new Random();
TreeSet<Integer> lotto = new TreeSet<Integer>();
while (true) {
int num = random.nextInt(45)+1;
System.out.println(num);
lotto.add(num);
if(lotto.size() == 6) {
break;
}
}
System.out.println(lotto);
}
List<E>
- 순서가 유지된다 ( 저장된 순서대로 다시 꺼낼 수 있다 )
- 요소가 저장될 때 마다 index가 자동으로 부여된다
- 특정위치에 요소 저장하기, 특정위치의 요소 삭제하기, 특정위치의 요소 꺼내기가 가능하다
List<E>가 지원하는 추가 메소드
메소드 종류 | 메소드 수행 내용 |
void add(int index, E e) | 지정된 위치에 요소를 저장 |
E get(int index) | 지정된 위치의 요소를 꺼낸다 |
E remove(int index) | 지정된 위치의 요소를 삭제 |
E set(int index, E e) | 지정된 위치의 요소를 새 요소로 교체 |
주요 구현 클래스
구현 클래스 종류 | 구현 클래스 수행 내용 |
ArrayList<E> | 가장 많이 사용하는 List 구현 클래스 ( 전체 자료구조 클래스 중에서 가장 많이 사용 ) |
LinkedList<E> | 더블링크로 List를 구현한 클래스 ( 요소의 추가 / 삭제 성능이 우수 ) |
Vector<E> | ArrayList와 유사하는 List구현 클래스 ( 멀티스레드 환경에 안전 ) |
Stact<E> | LIFO( Last-In-First-Out ) 으로 구현된 List 구현 클래스 |
ArrayList<E> : List<E> 인터페이스를 구현한 구현 클래스
가변길이 배열을 활용해서 List<E> 인터페이스를 구현.
순서가 보장되는 자료구조 클래스
ArrayList<E> 사용예제
public static void main(String[] args) {
// String 객체를 여러 개 저장할 수 있는 ArrayList 객체를 생성함
ArrayList<String> list = new ArrayList<String>();
// boolean add(E e) - ArrayList 객체에 순서대로 객체를 저장한다
// 맨 마지막번째 객체 다음에 저장된다
list.add("홍길동");
list.add("길동");
list.add("고길동");
list.add("신길동");
list.add("연희동");
list.add("장발장");
list.add("홍길동");
list.add("홍길동");
// int size() : ArrayList 객체에 저장된 객체의 갯수를 반환한다
int size = list.size();
System.out.println("저장된 객체의 개수 : " + size);
// 향상된 for문으로 ArrayList 객체에 저장된 String 객체 처리하기
for(String s : list) {
System.out.println(s);
}
}
ArrayList<E> 클래스 메소드 asList(T... t), of(E e) 사용예제
public static void main(String[] args) {
// new 키워드를 이용해서 List 인터페이스 구현체인 ArrayList 객체 생성하기
ArrayList<String> list = new ArrayList<String>();
List<String> list2 = new ArrayList<String>();
list2.add("고길동");
list2.add("장발장");
list2.add("신길동");
// Arrays 클래스 메소드 asList(T... t)를 이용해서 List 인터페이스의 구현객체 생성하기
//(T... t) = 가변길이 매개변수
List<String> list3 = Arrays.asList("고길동","길동","신길동");
// List 인터페이스의 클래스 메소드 of(E e)를 이용해서 List 인터페이스의 구현객체 생성하기
// 아래의 방법의 생성한 List는 불변객체
// 새로운 객체를 추가하거나, 기존 객체를 삭제할 수 없다
List<String> list4 = List.of("홍길동","산길동","산신령");
}
Iterator<E> 인터페이스
- 자료구조내의 각 요소를 순회하는 반복자 객체의 표준 인터페이스
- 모든 자료구조 구현클래스는 자신의 자료구조객체에 저장된 데이터를 하나씩 반복해서 조회할 수 있는 Iterator 객체를 구현하고 있다
- 모든 자료구조 구현객체는 Iterator 인터페이스를 구현한 Iterator 객체를 제공
- 모든 자료구조 구현객체가 제공하는 Iterator 구현객체는 구현내용은 다를 수 있지만 사용방법은 동일
= 모든 자료구조 구현객체는 동일한 사용법으로 자료구조내에 저장된 객체를 하나씩 조회할 수 있는 Iterator 구현객체를 제공하는 것
주요 메소드
메소드 종류 | 메소드 수행 내용 |
boolean hasNext( ) | 반복할 요소가 남아있는 true를 반환 |
E next( ) | 현재 반복대상이 되는 요소를 꺼낸다 |
void remove( ) | 현재 반복대상이 되는 요소 삭제 |
Iterator<E>
- Collection<E> 인터페이스의 모든 구현 클래스들은 Iterator iterator( ) 메소드를 구현
- ArrayList<E> 객체의 iterator( )를 실행하면 ArrayList의 각 요소를 순회하는 Iterator 구현객체가 획득된다
- HashSet<E> 객체의 iterator( )를 실행하면 HashSet의 각 요소를 순회하는 Iterator 구현객체가 획득된다
- LinkedList<E> 객체의 iterator( )를 실행하면 LinkedList의 각 요소를 순회하는 Iterator 구현객체가 획득된다
Iterator 실행예제
public static void main(String[] args) {
List<String> list = Arrays.asList("홍","고","길","동","황");
System.out.println("일반 for문을 사용해서 반복처리하기 - List 계열만 가능");
int size = list.size();
for(int index = 0; index<size; index++) {
String name = list.get(index);
System.out.println(name);
}
System.out.println("향상된 for문을 사용해서 반복처리하기");
for (String name : list) {
System.out.println("이름: "+name);
}
System.out.println("Iterator를 사용해서 반복처리하기");
Iterator<String> itr = list.iterator();
while (itr.hasNext()) { // hasNext()로 반복할 요소가 남았는지 확인하기
String name = itr.next(); // next로 요소 꺼내기
System.out.println(name);
}
System.out.println("Stream을 사용해서 반복처리하기");
list.stream().forEach(name -> System.out.println(name));
}
Iterator 실행중 요소 삭제예제
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("가");
list.add("나");
list.add("다");
list.add("라");
list.add("마");
list.add(null);
list.add("바");
list.add("바");
// 컬렉션의 remove(Object o)로
// 리스트객체에서 처음으로 발견되는 객체만 삭제한다
list.remove("바");
System.out.println(list);
// 향상된 for문으로 반복처리 중에 요소 삭제하기
// 향상된 for문으로 반복처리하는 도중에 컬렉션에 저장된 객체를 삭제할 수 없다
for(String name : list) {
if("바".equals(name)) {
// list.remove(name); //예외발생 ConcurrentModificationException
}
}
// Iterator로 반복처리 중에 요소 삭제하기
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
String name = itr.next();
if ("바".equals(name)) {
itr.remove();
}
System.out.println();
}
// 컬렉션에 대한 삭제를 하는 작업이면 Iterator를 사용 , 삭제하지 않으면 향상된 for문을 사용하는게 편리하다
}
결론
- Collection를 구현한 자료구조 구현클래스들은 자신의 자료구조에 저장된 각 요소를 순회하는 자신만의 Iterator 구현객체를 제공한다
- 각 자료구조 구현클래스들의 Iterator 구현내용은 다를 수 있지만, 사용방법은 동일한 구현 Iterator 객체를 제공한다
- 자료구조객체에 저장된 데이터를 순회하면서 현재 반복대상이 되는 객체를 삭제해야하는 경우에는 반드시 Iterator를 사용해야 한다
- 향상된 for문의 내부에서는 자료구조객체에 저장된 객체를 삭제할 수 없다