오늘의 포스팅은 컬렉션 프레임 워크 중에 우리가 흔히 인텔리제이 에서 iter 이란 키워드로 편하게 배열을 탐색하게 해주는 바로 그 기능에 대해 포스팅 하고자 한다!

사실 이전에 그냥 개꿀 기능이네~ 하고 블로그에 글을 썼던 주제인데.. 사실 알고보면 복잡하고 복잡한 기능을 우리가 그냥 쓰기 편하게 인터페이스로 구현해놓은 것이었다..


뭣도 모르고 사용 했던 향상된 for 문 (for - each)

https://bdisappointed.tistory.com/33

 

[Java] 향상된 for문 (for - each문)

향상된 for 문 (for - each)문이란배열을 배우고 응용하다 보면 배열의 0번째 인덱스부터 끝까지 한번 돌리고 싶은데,우리가 그럴 때마다 어떻게 했는가? 일단 아래 예시를 보자.//기존 for 문 사용publ

bdisappointed.tistory.com

지금 읽어보면, 저게 사실 뭔지도 모르고 그냥 단축키로 편하다니까 썼던건데, 지금 읽어보면 진짜 쓰레기 같군ㅋㅋ


순회란 무엇인가

먼저, 순회 란 무엇인가?

순회란, 여러 곳을 돌아 다닌 다는 뜻인데, 자료 구조에서의 순회란, 자료 구조 안에 있는 데이터에 차례대로 접근하여 처리 하는 것을 순회라고 한다.

하지만 이러한 자료구조들을 순회하는 방법은 각 자료구조마다 차이점이 있는데, 대표적으로

배열리스트는 그냥 처음 인덱스부터 마지막 인덱스까지 for문으로 값을 탐색하면 되고, 

연결리스트는 값과 다음 노드의 참조값을 한 노드안에 가지며, 다음 노드의 참조값을 통해 모든 노드를 순차적으로 순회하는 자료구조인 것처럼, 각 자료구조마다 데이터를 순회하는 방법이 다르다

그런데 만약 자료구조를 동일한 방법으로 순회할 수 있는 일관성 있는 방법이 존재한다면, 우리같은 애송이들은 매우 편리할 것이다!

이를 해결하기 위해 Java에서는 Iterable 인터페이스와 Iterator 인터페이스를 제공한다


Iterable, Iterator

먼저 두 단어의 뜻을 살펴보면,

Iterable = 반복 가능한, Iterator = 반복자 라는 의미를 가지고 있다.

ㅋㅋㅈㅅ

아무튼.. 위 두 인터페이스들은 각각 아래와 같은 주요 메서드를 구현하는데,

//Iterable 인터페이스
public interface Iterable<T> {
 Iterator<T> iterator();
}

단순히 Iterator 반복자를 반환하고,

//Iterator 인터페이스
public interface Iterator<E> {
 boolean hasNext();
 E next();
}

hasNext() 메서드를 통해 다음 요소가 존재하는지 확인하고, next 메서드를 통해 다음 요소를 반환하고, 현재 위치를 다음 요소로 옮기는 메서드들을 제공한다.

 

즉 결론적으로, 위 두 메서드를 통해 만약 자료구조가 Iterable(반복 가능) 하다면, Iterator(반복자)를 호출하여 다음과 같은 로직을 수행하면 된다

자료 구조야 다음 요소가 존재해 ? -> 존재한다면 다음 요소 꺼내고, 존재하지 않는다면 종료


Iterator 직접 구현해보기

import java.util.Iterator;

public class MyArrayIterator implements Iterator<Integer> {
    private int currentIndex = -1;
    private int[] targetArr;

    public MyArrayIterator(int[] targetArr) {
        this.targetArr = targetArr;
    }

    @Override
    public boolean hasNext() {
        return currentIndex < targetArr.length - 1;
    }

    @Override
    public Integer next() {
        return targetArr[++currentIndex];
    }
}

간단하게 요약하면, 

currentIndex 를 통해 최초에 인덱스를 사용할 위치를 정의하고, next() 를 호출할 때마다 1씩 증가시킨다.

또한, hasNext() 메서드를 오버라이딩하여 현재 인덱스가 배열의 끝까지 도달하는지 검증하는 조건검증 메서드이다.

next() 메서드는 다음 요소를 반환하는데, 최초의 인덱스를 0으로 해놔야 다음 항목을 검색할 때, 0번 인덱스를 가르킬 수 있으니 -1로 최초 커서를 설정해두었다.

다만 이렇게 구현한 Iterator 는 단독으로 사용이 불가하다. 위에서 말한 것 처럼 Iterator 이 사용가능하려면, Iterable 즉 반복이 가능한 조건이 필요하기 때문에, 우리는 Iterable 인터페이스도 구현해줘야 한다.


Iterable 직접 구현해보기

import java.util.Iterator;

public class MyArray implements Iterable<Integer> {

    private int[] numbers;

    public MyArray(int[] numbers) {
        this.numbers = numbers;
    }

    @Override
    public Iterator<Integer> iterator() {
        return new MyArrayIterator(numbers);
    }
}

내부에 숫자를 배열로 보관하는 단순한 자료구조이다.

다만 우리는 Iterable 즉 반복이 가능하도록 Iterable 인터페이스를 구현하여, 이 자료구조를 반복이 가능하게 끔 즉, Iterator 를 사용할 수 있도록 설계한 것이다.

Iterable 인터페이스를 구현하였으므로, 아까 위에서 언급했던 반복자를 반환하는 메서드를 오버라이딩 해주면 되는데, 여기서 우리는 우리가 만들었던 Iterator에 현재 배열 (numbers)를 넘겨 반복자를 반환 받을 수 있다.

즉 MyArrayIterator는 생성자를 통해 우리가 만든 자료구조 MyArray의 배열 numbers 를 참조하게 된다!


자 이제 두개를 써봅시다 - Main 메서드

import java.util.Iterator;

public class MyArrayMain {
    public static void main(String[] args) {

        MyArray myArray = new MyArray(new int[]{1, 2, 3, 4});

        Iterator<Integer> iterator = myArray.iterator();
        System.out.println("iterator 사용");
        while (iterator.hasNext()) {
            Integer value = iterator.next();
            System.out.println("value = " + value);
        }
    }
}

우리가 만든 자료구조는 Iterable 하므로 Iterator를 적용할 수 있게 되었다.

메인 메서드의 코드흐름을 살펴보자

1. 먼저 1,2,3,4로 구성된 배열의 참조값을 MyArray 생성자를 통해 넘기고, 또 그 넘긴 참조를 myArray 변수에 저장

2. myArray.iterator 메서드를 호출하여 1,2,3,4 의 참조를 가진 MyArrayIterator 인스턴스 반환

3. 반복문 (배열의 끝까지 즉 false가 나올 때 까지) 수행 -> value에 next() 메서드의 결과 값을 담고 출력

4. 배열의 마지막 인덱스까지 출력하면 다음 요소가 없으니 반복문 종료, 프로그램 종료

이런 너낌? 유남생?

 


간단 정리 =  Iterable 해야 Iterator를 쓸 수 있다.

아직 끝난건 아니지만, 포스팅이 길어지기 때문에 나눠서 쓸 예정이다.

아무튼, 오늘 내용의 핵심은 Iterable 해야 Iterator을 쓸 수 있다는 점이다.

즉, Iterable 하다면, Iterator을 호출하고, 

Iterator의 hasNext() 메서드를 통해 다음 노드가 존재하는지에 대한 유무를 검증하는 식을 통해 검증하고,

next() 메서드를 통해 다음 노드로 이동하여 이동한 노드의 값을 출력할 수 있게 되었다.

이렇게 되면 자료구조의 처음부터 끝까지 단순 두가지 메서드를 통해서 모든 데이터를 순회할 수 있게 되었다!

 

다음 포스팅은 for-each 문과 이 Iterable의 상관관계와 Java에서 제공하는 Iterable은 어떻게 동작하는지에 대해 포스팅 하겠다!

그럼 오늘도 20000!