2012년 10월 22일 월요일

자바의 반복자(Iterator)와 리스트반복자(ListIterator)


오늘은 컬렉션에 관계된 자바의 반복자인 Iterator와 리스트반복자인 ListIterator에 대해서 들여다보는 시간을 갖도록 하겠다. 자바의 벡터 시간 이후로 컬렉션이란 말을 간간히 쓰고 있는데 대충 이전에 간략하게 언급은 했지만 사실 이것에 대해서 구체적인 개념이 정립되어 있지 않은 이들은 컬렉션이란 말만 나와도 머리속이 어지러운 공황상태(?)로 돌입하고 있을지도 모르겠다.ㅎㅎ 그러나 염려놓기 바란다. 어느정도 궁금증이 증폭되었을때 관련 강의를 듣게되면 그것이 머리속으로 솔솔찮게 들어올 것이니 말이다. 다음 강좌에서 자바의 컬렉션에 대한 특강을 할것인데 아마도 그것을 듣게되면 그동안 쌓였던 궁금증과 의문점들이 눈녹듯이 한순간에 사라져버릴 것이다.ㅎㅎ 여러분의 많은 기대 부탁드리면서 다음 강의 광고는 잠시 접도록 하고 다시 본론으로 들어가보기로 하겠다.^^


java.util 팩키지에 들어있는 인터페이스 Iterator와 ListIterator를 공부해볼텐데 컬렉션이랑 관계되어 있으므로 배열을 떠올릴수 있을 것이고 반복이란 의미를 생각한다면 또한 자주 이용되고 계속 반복해서 뭔가(요소들)를 돌릴수 있구나라고 어거지(?)로 유추를 해보자.ㅎㅎ 또한 이름에서 보듯이 서로 연관성이 있음을 알수 있다. 어떻게 아냐고? Iterator란 단어가 둘다 들어가 잊지 않은가? ㅎㅎ 별거 아니라고 넘기는 이들이 많겠지만 자바의 모든 팩키지들, 인터페이스들, 클래스들, 메소드들, 기타등등,, 이름만 관심있게 보아도 반은 먹고 들어갈수 있다. 자바는 이름을 지을때도 기능과 연관이 있도록 심혈을 기울여만든 프로그래밍의 걸작(?)이기 때문에 그러하다.^^

Iterator는 개체의 요소들을 출력할때 기존의 인덱스 증감인자에 의존하던 방식을 탈피해서 보다 편리하고 쉽게 출력이 가능하도록 만들어준다. Iterator는 자바 컬렉션 내부에서 자유롭게 쓸수 있으며 기존의 Enumeration의 기능을 완전히 대체함과 동시에 remove( ) 메소드를 장착하고 메소드명들도 줄여서 편리하게 쓸수 있도록 개선되었다. 따라서 구식인 Enumeration을 쓸 필요가 전혀 없다. 필자가 벡터 강의할때 잠시 어떻게 쓰는지 보여줬을텐데 이 시간 이후부터는 더 향상된 기능인 Iterator만 쓰기로 하니 여러분도 Enumeration은 깨끗이 잊어주기 바란다. 헐~ 그럼 처음부터 Iterator만 설명하지 왜 Enumeration을 보여줘서 혼란을 가중시키냐고 딴지거는 이들은 듣기바란다. 그럼 Iterator 나오기 이전에 작성된 프로그램들을 보았을때 이해는 할수 있어야하지 않겠느냐? 답이 됐나? ^^ 그럼 됐다.ㅎㅎㅎ

여러분에 대한 사랑(?)이 깊어지는 관계로 자꾸 서론이 길어지고 있다. 이제 정신을 가다듬고 Iterator가 어떤 메소드들을 가지고 있는지 살펴보기로 하자.^^

boolean hasNext( )
E next( )
void remove( )

위의 딱 3가지 메소드 밖에 가지고 있지 않다. 따라서 여러분이 이 세가지 메소드들의 기능만 쓸줄 알면 Iterator의 종결자(?)로 바로 등극할수 있으니 더도말고 3분만 여기에 시간을 투자하기 바란다.ㅎㅎ 뭘 기대하는거냐? 여기에 대해서 부연설명은 하지 않겠다. 여러분이 강이의 자바강좌를 열공했다면 이 정도쯤이야 메소드 구조만 딱 봐도 탁탁~ 아닌감? ㅎㅎ
그래도 배려심(?)이 깊다리깊은 필자가 한마디 하자면 hasNext( ) 메소드를 보면 뭔가 다음꺼를 찾는다는 것이고 리턴타입을 보니 boolean이란다. 그럼 자동적으로 리턴값이 true나 false를 돌려준다는 것이니 if나 while문 같은 컨디션에 쓰기 딱 좋다는 것을 알아차릴수 있다.ㅎㅎ next( ) 메소드야 보자마자 다음껀데 리턴타입에 E가 떡하니 붙어있으니 어떤 데이터형인지는 모르겠지만 element값을 돌려주는구나 하고 생각하면 되고 remove( ) 메소드는 말그대로 없애는 기능이구나 생각하면 되시겠다. 한마디가 너무 길었나? ㅎㅎ

이제 ListIterator를 살펴보자. ListIterator는 상위계층의 Iterator를 그대로 계승한다. 따라서 Iterator의 기능은 기본적으로 갖추고 있으며 Iterator와 크게 다른점은 양방향으로 리스트를 돌면서 관련 요소들을 출력할수 있다는 것이다. 관련 메소드들은 다음과 같은 것들이 있다.

boolean hasNext( )
E next( )
void remove( )
int nextIndex( )
boolean hasPrevious( )
E previous( )
void add(E e)
int previousIndex( )
void set(E e)

아까 필자가 한것처럼 메소드들이 어떤 기능을 가지고 있는지 탁탁~ 보기 바란다. 대충 어떤 기능들이 있는지 쉽게 눈에 들어올 것이라 믿겠다.^^ 리스트반복자는 기존 반복자에 비해서 어떻게 동작하는지에 대한 구조정도는 머릿속으로 그릴수 있어야 하는데 그 이유는 양방향으로 움직이기 때문에 상황에 따라 앞으로 갔다 뒤로 갔다거리면 자칫 무한루프에 빠질수 있기 때문이다. 여러분의 이해를 돕기 위해 특별히 그림으로 설명하겠다.^^


기존의 배열이라면 인덱스가 그냥 관련 요소를 지칭하지만 반복자에서는 위처럼 커서가 요소(Element)를 지칭하는게 아니라 요소들의 사이 사이를 지칭한다고 생각하여야 정확하다. 특히 이 개념은 리스트반복자(ListIterator)를 사용할때 더욱 중요한 개념으로 next( ) 메소드와 previous( ) 메소드를 연속해서 사용할시 기존에 쓰던 배열에서의 인덱스를 생각한다면 서로 다른 요소를 넘겨받는다고 생각하겠지만 위의 그림과 같은 인덱스 방식으로는 같은 요소를 주고받게된다. 이해가 안되면 아래 그림을 보면서 생각해보면 금새 알게 될것이다.^^


이제 이해가 되는가? 지금 위의 그림은 반복자가 next( ) 메소드를 이용해 옆으로(?) 이동했을때 그 사이에 있는 요소를 돌려준다는 것을 그림으로 표현하고 있는 것이다. 많은 이들이 반복자를 사용하고 있지만 그 원리를 제대로 모르고서 그냥 무작정 사용하고 있는 이들이 많은데 그럴경우 원치않는 요소가 가끔 튀어나올 것이다. 그건 여러분이 반복자가 어떻게 작동하고 있는지 제대로 알고 있지 못하기에 그런 상황을 겪게 되는데 강이의 자바강좌를 필독하는 이들은 이 정도의 레벨(?)은 바로 뛰어넘어 다른 미지의 세계로 나아가야할 것이다.ㅎㅎ

반복자를 공부하면서 혹시 이런 생각을 하는 이들이 있을지도 모르겠다. 아 그냥 루프는 기존의 for 룹으로 전부 다 통일하는게 오히려 더 편하지 않을까? 이런 신통방통(?)한 질문을 던지는 이들이 있을텐데 필자는 이런 여러분에게 박수를 치고 싶으나 이 사실을 알고나면 왜 반복자가 그렇게 많이 쓰이는지 알게 될것이다. 뭘까? ㅎㅎ 예를 들어 기존 배열에서 쓰는 for 룹으로 리스트를 출력한다고 치자. 그럼 이 for 룹은 인덱스 중심으로 읽히므로 리스트가 수정이 된다면 for 구문도 그에 맞춰서 같이 수정되야한다. 리스트의 길이가 어떻게 바뀔지 모르니까 말이다. 허나 반복자를 이용하면 리스트가 수정이 가해지든 않든 상관없이 최종 상태의 리스트를 넘겨받아 작동되므로 반복자를 이용한 루프 구문은 손댈 필요가 없게 되니 더 편하다.^^

물론 확장된 enhanced for 루프(for-each)도 메카니즘이 반복자를 이용하는 것이기 때문에 마찬가지다.ㅎㅎ 그럼 또 이런 질문을 하는 이들이 있을 것이다. for-each 루프문을 쓰지 왜 Iterator를 이용하는냐고 말이다.ㅎㅎ 여러분이 리스트에 변형을 가하지 않고 단순히 리스트에서 요소들을 처음부터 끝까지 출력만 하는 경우에는 Java 5에서 새로 등장한 for-each 루프문을 쓰는게 최고라고 할수 있겠다. 왜냐하면 Iterator의 경우 hasNext( ) 메소드를 이용해서 다음 요소가 있는지 확인을 해야하는데 확장된 for 루프문은 이런 과정을 우리가 수동으로 체크하지 않아도 되도록 만들어놨기 때문이다. 이번 강의의 제목이 반복자여서 반복자를 이용해 출력한 것이지 만약 다른 곳에서 단지 리스트를 출력하기만 하면 되는 경우라면 당근 자바5 신무기(?)로 무장된 enhanced for 루프문을 쓰는게 현명할 것이다.^^

이제 반복자에 대한 설명은 어느정도 정리된것 같으니 필자의 특화된 예제를 통해 Iterator와 ListIterator의 핵심동작원리를 깨우치기 바라면서 오늘의 강좌를 마치도록 하겠다. 본 예제는 반복자를 이용해 어떻게 요소들을 출력하는지 가장 기본적이면서도 빈번하게 쓰이는 방식이니 잘보고 앞으로 많이 써먹기 바란다.^^


오늘 예제는 아주 뜻깊은 예제라 할수 있겠다.- 필자가 강이의 자바강좌 예제 최초로 빨간줄을 도입한 혁신의 날(?)이기 때문이다. 그 전에 한적이 있었나? 그럼 말구~ㅎㅎ 어쨌거나 이번 예제에 빨간줄 치느라 무지 애먹었는데 그에 따른 피땀어린 노력(?)이 바래지지 않도록 더더욱 열심히 공부해주기 바란다.ㅎㅎ

예제에 있는 빨간박스 3개만 집중해서 보면된다. 나머지는 다 아는 내용일테고 첫번째 박스는 Iterator를 이용해 리스트를 출력하는 예제이고 두번째 박스는 ListIterator를 이용해 리스트를 출력하는 예제이고 마지막 세번째 박스는 ListIterator를 이용해 리스트를 거꾸로 출력하는 예제이다. 마지막 박스야말로 ListIterator가 Iterator와는 다르게 할수 있는 큰일(?)이라 할수 있겠다. 예제를 보면 그냥 이해가 될것이니 특별한 부연설명은 필요없겠지만 굳이 하나를 들춰보자면 al.iterator( )와 al.listIterator( ) 정도일꺼다. 필자가 제대로 궁금한거 찍었남? Arraylist의 al은 인터페이스 List와 관련되어 있다. 이 인터페이스 List를 구현한 클래스 중에 하나가 Arraylist인데 그 안에 위와 같이 반복자가 돌아다닐수 있는 Iterator나 ListIterator 형식으로 리스트를 받을수 있게 해주는 메소드가 들어있어서 기존의 리스트를 이렇게 그대로 쉽게 넘겨받을수 있는 것이다.^^ 이것 빼고는 여러분이 프로그램 돌려보면 별 어려운 사항이 없을테니 필자는 예제 결과값을 공개하면서 이번 강의를 마치도록 하겠다. 아래를 보기 전에 예제에 대한 결과값을 미리 예상해보고 여러분의 답과 맞춰보면서 공부하는 센스(?)장이가 되기를 희망하면서 물러가겠다.^^

ArrayList(itr): A B C D E
=== 강이의 JAVA강좌 ===
ListIterator(forward): A B C D E
=== http://alecture.blogspot.com ===
ListIterator(backwards): E D C B A

댓글 3개: