Java의 정석 3판을 보며 공부한 내용을 정리하였습니다.
남궁성님께 많이 배우고 있습니다.
이 셋은 모두 컬렉션에 저장된 요소를 접근하는데 사용되는 인터페이스이다.
컬렉션에 저장된 요소들을 읽어오는 방법을 표준화
저장된 각 요소에 접근하는 기능을 가진 Iterator인터페이스를 정의
Collection 인터페이스에는 Iterator를 반환하는 iterator()를 정의
(List, Set은 Collection를 상속하므로 iterator()가 있음.)
iterator()를 호출해서 Iterator를 얻어서 반복문을 사용해서 각 요소에 접근
public interface Iterator {
boolean hasNext();
object next();
void remove();
}
public interface Collection {
...
public Iterator iterator();
...
}
Collection c = new ArrayList(); // 다른 컬렉션으로 변경시 이 부분만 고치면 된다.
Iterator it = c.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
ArrayList 대신 Collection 인터페이스를 구현한 다른 컬렉션 클래스에서도 동일하게 사용 가능하다.
표준화했기 때문에 이렇게 코드의 재사용성이 높다.
Collection c = ArrayList(); // ArrayList 사용 시
Collection c = LinkedList(); // LinkedList 사용 시
아래는 관련 예제이다.
...
public static void main(String[] args){
ArrayList list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
Iterator it = list.iterator();
while(it.hasNext()) {
Object obj = it.next();
System.out.println(obj);
}
}
...
List는 저장순서를 유지하므로 Iterator를 이용해서 읽은 결과 역시 저장순서와 동일하지만
Set클래스들은 각 요소간 순서가 유지되지 않아서 Iterator로 읽은 요소는 저장순서와 같지 않다.
Map 인터페이스를 구현한 컬렉션 클래스는 키(key)와 값(value) 을 쌍(pair) 으로 저장하기 때문에, iterator()를 직접 호출 불가!
대신 keySet()이나 entrySet()과 같은 메서드를 통해 키와 값을 각각 Set 형태로 얻어서 다시 iterator()를 호출해야 Iterator를 얻을 수 있다.
Map map = new HashMap();
...
Iterator it = map.extrySet().iterator(); // 아래의 주석 문장 두개를 하나로 합친 것
/*
Set eSet = map.extrySet();
Iterator it = eSet.iterator();
/*
Iterator it = map.extrySet().iterator(); // Iterator it = Set인스턴스.iterator();
Iterator it = Set인스턴스.iterator(); // Iterator it = Iterator인스턴스;
StringBuffer 사용 시 아래와 같이 코드를 쓴다.
StringBuffer sb = new StringBuffer();
sb.append("A");
sb.append("B");
sb.append("C");
이 코드는 아래와 같이 간단히 쓸 수 있다.
StringBuffer sb = new StringBuffer();
sb.append("A").append("B").append("C");
append 메서드가 StringBuffer로 반환하기 때문이다.
Enumeration은 컬렉션 프레임웍이 만들어지기 이전에 사용하던 것으로 Iterator의 구버전과 같다.
이전 버전과의 호환을 위해 남겨둔 것이므로 가능하면 Enumeration 대신 Iterator를 사용하자.
ListIterator는 Iterator를 상속받아 기능을 추가한 것
Iterator는 단방향이지만, ListIterator는 양방향 이동 가능!
(단, ArrayList나 LinkedList와 같이 List인터페이스를 구현한 컬렉션에서만!)
Enumeration과 Iterator는 메서드 이름만 다를 뿐 기능은 같다.
(ListIterator는 Iterator + 이전방향으로 접근기능)
public static void main(String[] args){
ArrayList list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
ListIterator it = list.listIterator();
while(it.hasNext()) {
System.out.print(it.next()); // 순방향으로만 진행하면서 읽는다.
}
System.out.println();
while(it.hasPrevious()) {
System.out.print(it.previous()); // 역방향으로만 진행하면서 읽는다.
}
System.out.println();
}
next()나 previous()로 이동하기 전에 꼭 hasNext() 나 hasPrevious()로 확인해야 한다.
선택적 기능들은 꼭 구현하지 않아도 된다. 하지만 인터페이스로부터 상속받은 메서드는 추상메서드라 메서드의 몸통(body)를 반드시 만들어 줘야 하므로 다음과 같이 처리한다.
public void remove() {
throw new UnsupportedOperationException();
}
단순하게 public void remove(){}; 와 같이 구현하기보다는 위와 같이 예외를 던져서 구현되지 않는 기능이라는 것을 메서드 호출한 곳에 알리는 것이 좋다.
Java API 문서에 remove()의 상세 내용을 보면 remove메서드를 지원하지 않는 Iterator는 UnsupportedOperationException을 발생시킨다고 쓰여 있다.
즉, remove메서드를 구현하지 않으면 UnsupportedOperationException을 발생시키도록 구현하라는 뜻이다.
...
public static void main(String[] args){
MyVector2 v = new MyVector2();
v.add("0");
v.add("1");
v.add("2");
v.add("3");
v.add("4");
System.out.println("삭제 전 : " + v);
Iterator it = v.iterator();
it.next();
it.remove();
it.next();
it.remove();
System.out.println("삭제 후 : " + v);
}
...
MyVector2객체를 생성하고 데이터를 저장한 뒤 Iterator를 통해 첫 번째와 두 번째에 저장된 데이터를 삭제한다.
출력결과 :
삭제 전 : [0, 1, 2, 3, 4]
삭제 후 : [2, 3, 4]