본문 바로가기
Java

Iterator,Iterable

by 스르나 2021. 2. 13.

자바에서는 ArrayList,LinedList등 자료를 탐색할 수 있는 Collection이 존재한다.

 

하지만 이런 Collection들은 탐색방법을 우리가 임의로 정하지 못한다. 예를들어 총 10개가 저장돼있는 선형적 자료구조에서 짝수번째만 보고싶다하더라도 for,forEach를 통해 인덱스를 홀수번째라면 건너뛰고 확인해야 한다.

public class Main {
    public static void main(String[] args) {
        ArrayList<String> test=new ArrayList<>();

        test.add("사과");
        test.add("딸기");
        test.add("오렌지");
        test.add("포도");
        test.add("참외");
        test.add("파인애플");
        
        for(int i=0;i<test.size();i++){
            if(i%2==0){ //인덱스가 짝수인것만 체크
                System.out.println(test.get(i));
            }
        }
    }
}

 

이럴때 우리가 Iterator,Iterrable을 이용한다면 우리가 정한대로 탐색을 할 수 있다.

 

사용방법은 우선 한 클래스에서 Iterable인터페이스 를 구현하는 것으로 시작한다.

 

Iterable 인터페이스의 원형을보자

 

public interface Iterable<T> {
    /**
     * Returns an iterator over elements of type {@code T}.
     *
     * @return an Iterator.
     */
    Iterator<T> iterator();
    
    //이하 생략
    
}

강제로 구현해야하는 메소드는 iterator하나이다. 이 iterator메소드는 Iterator인터페이스를 반환하는 것이 전부이다.

 

그럼 Iterator인터페이스도 한번 보자

 

public interface Iterator<E> {
	boolean hasNext();
    E next();
    
}

이 Iterator인터페이스는 hasNext와 next 메소드로 구성되어있으면 hasNext는 탐색할것이 더 남아있는지 boolean을 리턴하고  next는 다음 값을 넘겨주는 것이다. 이 hasNext,next 메소드를 우리가 원하는 탐색 방식으로 구현하면 선형적으로 탐색을 할 수도있고 다른 방식으로 탐색을 할 수도 있다.

 

그럼 Iterable,Iterator를 구현하는 방법을 보자

 

public class FruitShop<T extends Fruit> implements Iterable<T> {
    private ArrayList<T> basket;

    public FruitShop(){
        basket=new ArrayList<>();
    }

    public void addFruit(T fruit){
        basket.add(fruit);
    }

    @Override
    public Iterator<T> iterator() {
        return new FruitBasket(); //Iterator를 구현한 내부 클래스
    }

    private class FruitBasket implements Iterator<T>{
        private int cursor=0;
        @Override
        public boolean hasNext() {
            return cursor<basket.size();
        }

        @Override
        public T next() {
            int i=cursor;
            cursor++;
            return basket.get(i);
        }
    }
}

위 코드는 Fruit를 상속받은 클래스를 저장하고 리턴해주는 클래스이다.

우선 클래스의 선언에 Iterable을 상속받았다. 그리하여 안에는 강제로 iterator메소드를 강제로 구현하는데 iterator의 반환을 위한 Iterator를 내부 클래스를 작성해서 만들었다.

 

이 내부클래스는 Iterator를 상속받았기때문에 hasNext와 next를 구현해야한다.

여기서 hasNext를 보면 cursor라는 정수현 변수와 실제로 데이터를 저장할 ArrayList의 사이즈를 비교함으로 구현했다.

다음으로 next는 현재 cursor에 해당하는 값을 리턴해주면서 cursor의 값을 늘리는 것으로 구현했다. 즉, 그냥 0번부터 선형적으로 탐색하는 방식이다.

 

그럼 사용 방법을 보자

 

public class Main {
    public static void main(String[] args) {
        FruitShop<Apple> appleFruitShop=new FruitShop<>();

        appleFruitShop.addFruit(new Apple());
        appleFruitShop.addFruit(new Apple());
        appleFruitShop.addFruit(new Apple());
        appleFruitShop.addFruit(new Apple());
        appleFruitShop.addFruit(new Apple());
        appleFruitShop.addFruit(new Apple());


        Iterator<Apple> itr=appleFruitShop.iterator(); // 일회용이다!

        while(itr.hasNext()){
            System.out.println(itr.next().getName());
        }

        System.out.println();

        appleFruitShop.forEach(apple -> System.out.println(apple.getName())); //forEach 로 만들 수 있다. 
    }
}

사용은 우선 iterator메소드를 통해 Iterator를 만드는것으로 시작한다. 그다음 리턴받은 Iterator의 hasNext와 next를 이욯해 사용하는것이 전부이다.

 

다음 사용방법은 forEach문인데 Iterable,Iterator에 forEach가 구현되어있기 때문에 저렇게 사용할 수 있다.

'Java' 카테고리의 다른 글

자바 synchronized 이해  (0) 2021.02.24
JVM  (0) 2021.02.14
Thread-3  (0) 2021.02.12
Thread-2  (0) 2021.02.11
Thread-1  (0) 2021.02.08