여행을 개발하다

[Java] Iterator(반복자) 본문

BackEnd/Java

[Java] Iterator(반복자)

yhtragramming 2021. 9. 2. 15:05

 

Java의 Iterator 인터페이스에 대해 공부해보았다.

 

Iterator를 우리 말로 번역하면 '반복자'로, 객체 지향 프로그래밍에서 배열과 같은 여러 개의 데이터의 집합으로 이루어진 자료구조를 순회하는 객체를 의미한다.

 

자바의 Iterator 인터페이스는 컬렉션 프레임워크에 저장된 요소들을 순회하여 읽어오는데 사용되는데, 어떤 컬렉션 프레임워크라도 읽어볼 수 있는 표준화된 방법을 제공한다. 물론, 대표적인 제어문인 for, while 문으로도 반복문을 얼마든지 가능하지만, Iterator는 '표준화된 방법을 제공'한다는 점에서 다형성을 구현하고자 했다.

 

그렇다면 컬렉션 프레임워크는 무엇일까?

 

1. Collection Framework(컬렉션 프레임워크)란?

프로그래밍을 할 때면, 우리는 일반적으로 발생되는 데이터를 '어떻게 처리할까?'를 고민하고 알고리즘을 구상한다. 하지만 매번 달라지는 이 데이터의 자료구조에 따라 조작 방식을 새로 정의하는 것은 여간 힘든 일이 아니다.

 

다행스럽게도 이러한 데이터 형식에 따른 처리 방식이 이미 클래스나 인터페이스의 형태로 정의가 되어있다. 예를 들어, key-value 형식은 HashMap(Map), 발생되는 데이터가 여러 개의 리스트 형식이면 ArrayList(List)를 사용하는 것이 그 대표적인 예이다.

 

이처럼 데이터를 처리하는 방식을 구조화하여 설계해 놓은 것을 'Collection Framework(컬렉션 프레임워크)'라고 한다. 자바의 컬렉션 프레임워크의 구조는 아래 다이어그램을 참조(처음 보는 것도 많아서 앞으로 공부하며 더 뜯어보기로 다짐했다).

자바 컬렉션 프레임워크의 구조 (출처 :   https://www.scientecheasy.com/2020/09/collection-hierarchy-in-java.html/ )

 

2. Enumeration의 전신(前身)

Iterator의 전신은 자바 초창기의 Enumeration 인터페이스이다.

 

기능은 Iterator와 마찬가지로 연속적인 요소에 대한 반복 호출이며, hasMoreElements(), nextElement()의 2가지의 메서드를 지원한다. 이는 아래와 같이 Iterator의 2가지 메서드와 대응되는데, 메서드명과 소속 인터페이스만 다를 뿐 구현하는 기능은 동일하다.

Enumeration - Iterator 비교

jdk 1.2부터 컬렉션 프레임워크의 개념이 도입됨으로써, Iterator 인터페이스가 함께 등장했다. Iterator 인터페이스는 Collection 인터페이스를 구현 및 상속한 모든 컬렉션 클래스에서 사용 가능하다.

 

아래는 항목 4, 예제를 Enumeration 인터페이스로 구현한 예제이다.

import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;

public class IteratorTest {
	
	public static void main(String[] args){
		
	  ArrayList<String> list = new ArrayList<>();
	  list.add("봄");
	  list.add("여름");
	  list.add("가을");
	  list.add("겨울");
	  
	  Enumeration<String> em = Collections.enumeration(list);
	  
	  while(em.hasMoreElements()) {
		  System.out.println("em.nextElement==>" + em.nextElement());
	  }
	  
	}
}

// 실행결과
// em.nextElement==>봄
// em.nextElement==>여름
// em.nextElement==>가을
// em.nextElement==>겨울

 

3. Iterator 관련 메서드

Iterator 인터페이스가 제공하는 메서드는 3가지로 꽤 단순하다. 또한, '반복자'라는 이름답게 while, for 문과 함께 사용된다.

① hasNext()

→ 다음 요소가 존재하는지 혹은 그렇지 않은지 true/false로 리턴한다. true 이면 다음 요소다 있다는 것이고, false 이면 현재 요소가 마지막이라는 뜻이다.

 

② next()

→ 다음 요소를 가져온다.

 

③ remove()

→ next()로 호출된 요소를 제거한다.

 

메서드의 종류를 순번을 붙여 나열한 이유는, Iterator에서 내부적으로 호출하는 메서드의 순서가 ① hasNext() → ② next() → ③ remove() 이기 때문이다.

 

4. 예제

ⓐ Iterator 인터페이스로 요소 읽어오기

① String 형태의 ArrayList를 선언하고, (봄, 여름 가을, 겨울)을 리스트에 추가해 준다.

import java.util.ArrayList;
import java.util.Iterator;

public class IteratorTest {
	
	public static void main(String[] args){
		
		ArrayList<String> list = new ArrayList<>();
		list.add("봄");
		list.add("여름");
		list.add("가을");
		list.add("겨울");
		
	}
}

 

② ArrayList를 Iterator 객체로 생성해 준다.

Iterator<String> itr = list.iterator();

 

③ 요소를 하나씩 뽑아 출력한다.

while(itr.hasNext()){
	System.out.println("itr.next()==>" + itr.next());
}

 

※ 실행 결과

import java.util.ArrayList;
import java.util.Iterator;

public class IteratorTest {
	
	public static void main(String[] args){
		
		ArrayList<String> list = new ArrayList<>();
		list.add("봄");
		list.add("여름");
		list.add("가을");
		list.add("겨울");
		
		Iterator<String> itr = list.iterator();
		
		while(itr.hasNext()){
			System.out.println("itr.next()==>" + itr.next());
		}
		
	}
}
// 실행결과
// Before==>봄
// Before==>여름
// Before==>가을
// Before==>겨울

※ 주의사항

한 번 사용된 Iterator 객체는 재사용이 불가능하다. 아래의 두 번째 호출된 반복문에 사용된 Iterator의 객체 itr은 이미 첫 번째에서 사용되었기 때문에, 아예 while 루프를 타지 않는다.

public static void main(String[] args){
  ArrayList<String> list = new ArrayList<>();
  list.add("봄");
  list.add("여름");
  list.add("가을");
  list.add("겨울");

  Iterator<String> itr = list.iterator();

  while(itr.hasNext()){
     System.out.println("list==>" + itr.next());
   }

  while(itr.hasNext()){
    System.out.println("list2==>" + itr.next());
  }
}
// 실행결과
// list==>봄
// list==>여름
// list==>가을
// list==>겨울

 

ⓑ remove() 메서드 사용하여 다음 요소 삭제하기

remove를 메서드는 현재 인덱스의 요소가 아닌 다음 인덱스의 요소를 삭제한다.

 

위 예제와 똑같은 코드에 다음 요소를 제거하는 'itr.remove()'를 추가했는데 결과는 똑같이 출력된다. 그 이유는 'itr.next()' 메서드가 다음 요소를 호출한 후, 삭제(itr.remove())가 진행됐기 때문이다.

while(itr.hasNext()){
    System.out.println("itr.next()==>" + itr.next());  // 다음 요소 출력
	itr.remove(); // 다음 요소 삭제
}

// 실행결과
// itr.next()==>봄
// itr.next()==>여름
// itr.next()==>가을
// itr.next()==>겨울

 

하지만, 메서드 순서만 바꾸면 에러가 발생한다. 그 이유는 이미 다음 요소가 삭제된 이후에, 해당 요소를 호출했기 때문이다.

while(itr.hasNext()){
  itr.remove(); // 다음 요소 삭제
  System.out.println("itr.next()==>" + itr.next());  // 다음 요소 호출(에러)
}

// 실행결과
// Exception in thread "main" java.lang.IllegalStateException
//	at java.base/java.util.ArrayList$Itr.remove(ArrayList.java:980)
//	at IteratorTest.main(IteratorTest.java:16)

 

지금까지 자바의 'Iterator(반복자)'에 대해 알아보았다.

 

감사합니다 : )

'BackEnd > Java' 카테고리의 다른 글

[Java] Optional(Optional<T>)  (0) 2021.12.31
[Java] TreeMap  (0) 2021.12.21
[Java] Servlet, HttpServletRequest 인터페이스(Interface)  (0) 2021.08.27
[Java] Thread (스레드)  (0) 2021.08.15
[Java] Wrapper Class(래퍼 클래스)  (0) 2021.08.04
Comments