본문 바로가기
Old Posts/Java

[Java] 'for each' 구문에서 사용할 클래스 구현

by A6K 2021. 7. 25.

자바에서 컬렉션에 들어있는 데이터를 순회하면서 처리할 때 반복문을 많이 사용한다. 가장 기본적으로 배열에 들어있는 데이터들을 하나씩 꺼내 출력하는 코드는 다음과 같다.

public static void main(String[] args) {

    int array[] = {1, 2, 3, 4, 5};

    for (int i = 0; i < array.length; i++) {
          System.out.println(array[i]);
    }
}

// 출력
// 1
// 2
// 3
// 4
// 5

초기부터 자바를 사용해왔거나 C언어 같은 언어롤 사용하던 프로그래머라면 이런 형태의 반복문이 자연스럽다. 하지만 자바는 컬렉션 데이터나 배열의 접근을 좀더 편하게 제공하기 위해서 'for each' 구문을 JDK 5.0 버전부터 제공하기 시작했다.

public static void main(String[] args) {

    int array[] = {1, 2, 3, 4, 5};

    for (int number : array) {
          System.out.println(array[i]);
    }
}

// 출력
// 1
// 2
// 3
// 4
// 5

컬렉션에 들어있는 데이터를 하나씩 꺼내서 접근하는 깔끔한 코드가 작성되었다. 반복문을 이용해서 배열을 접근할 때 배열 인덱스를 하나씩 증가시키면서 사용해야했던 코드들이 전부 깔끔하게 정리되었다. 이렇게 배열을 접근하면 IndexOutOfBoundsException 같은 위협이 사라지게된다.

for each 구문을 사용할 때 주의해야 할 점은, for each 구문으로 컬렉션 데이터를 접근할 때 컬렉션은 수정할 수 없다는 점이다.

for each 구문에 사용할 수 있는 클래스

for each 구문에는 이미 자바에서 정의되어 있는 컬렉션 데이터들을 사용할 수 있다. 뿐만아니라 사용자가 정의한 클래스도 컬렉션처럼 for each 구문에 사용할 수 있다. 다만 for each 구문에 사용하려면 'java.lang.Iterable' 인터페이스를 구현해야한다. 이 인터페이스를 구현하면 for each 구문에서 사용할 수 있다.

DB에 연결해서 테이블 데이터를 가져오거나 파일 서버에서 레코드를 하나씩 꺼내오는 클래스를 구현해서 for each 구문에 사용할 수 있다. 그러면 코드가 한결 깔끔해진다.

public class Test {

    public static void main(String []args) {

        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);

        TestIterable<Integer> testIterable = new TestIterable<Integer>(list);

        for (int item : testIterable) {
             System.out.println(item);
         }
     }
}

for each 구문에 사용한 testIterable 객체는 분명 컬렉션 타입은 아니다. TestIterable 클래스의 정의를 살펴보자.

public class TestIterable<Integer> implements Iterable<Integer> {

    class TestIterator<Integer> implements Iterator<Integer> {

        private final List<Integer> list;

        public TestIterator(List<Integer> list) {
            this.list = list;
        }

        public boolean hasNext() {

            return list.size() > 0;
        }

        public Integer next() {

            return list.get(0);
        }

        public void remove() {

            list.remove(0);
        }
    }

    private final Iterator<Integer> iterator;

    public TestIterable(List<Integer> list) {

        iterator = new TestIterator<Integer>(list);
    }

    public Iterator<Integer> iterator() {

        return iterator;
    }
}

Integer 데이터를 반환해주도록 지내릭 타입을 주고 Iterable 인터페이스를 구현했다. Iterable 인터페이스는 Iterator 객체를 리턴하게 되는데, Iterator 인터페이스를 구현한 클래스도 정의해 줬다.

for each 구문을 사용하면 코드가 깔끔해지고 가독성도 높아지는 장점을 얻을 수 있다.

댓글