1. 개요
이 사용방법(예제)에서는 Java에서 Iterable 및 Iterator 인터페이스의 사용법과 차이점을 살펴봅니다 .
2. 반복 가능한 인터페이스
Iterable 인터페이스는 java.lang 패키지에 속합니다반복할 수 있는 데이터 구조를 나타냅니다.
Iterable 인터페이스는 Iterator 를 생성하는 메서드를 제공 합니다 . Iterable 을 사용할 때 인덱스로 요소를 가져올 수 없습니다. 마찬가지로 데이터 구조에서 첫 번째 또는 마지막 요소도 가져올 수 없습니다.
Java의 모든 컬렉션은 Iterable 인터페이스를 구현합니다.
2.1. Iterable 에 대한 반복
for -each 루프 라고도 하는 향상된 for 루프 를 사용하여 컬렉션 내의 요소를 반복할 수 있습니다 . 그러나 Iterable 인터페이스를 구현하는 객체만 그러한 문 내에서 사용할 수 있습니다. Iterator 와 함께 while 문을 사용하여 요소를 반복하는 것도 가능합니다 .
for -each 문 을 사용하여 List 의 요소를 반복하는 예를 살펴보겠습니다 .
List<Integer> numbers = getNumbers();
for (Integer number : numbers) {
System.out.println(number);
}
마찬가지로 forEach() 메서드를 람다 식과 함께 사용할 수 있습니다.
List<Integer> numbers = getNumbers();
numbers.forEach(System.out::println);
2.2. Iterable 인터페이스 구현
Iterable 인터페이스 의 사용자 정의 구현은 반복하려는 사용자 정의 데이터 구조가 있을 때 유용할 수 있습니다.
배열에 요소를 담을 장바구니를 나타내는 클래스를 만드는 것으로 시작하겠습니다. 어레이에서 직접 for -each 루프를 호출하지 않습니다 . 대신 Iterable 인터페이스를 구현할 것입니다. 우리는 고객이 선택한 데이터 구조에 의존하는 것을 원하지 않습니다. 클라이언트에게 반복 기능을 제공하면 클라이언트가 코드를 변경하지 않고도 다른 데이터 구조를 쉽게 사용할 수 있습니다.
ShoppingCart 클래스는 Iterable 인터페이스를 구현 하고 iterate () 메서드 를 재정의합니다 .
public class ShoppingCart<E> implements Iterable<E> {
private E[] elementData;
private int size;
public void add(E element) {
ensureCapacity(size + 1);
elementData[size++] = element;
}
@Override
public Iterator<E> iterator() {
return new ShoppingCartIterator();
}
}
add() 메서드 는 요소를 배열에 저장합니다. 배열의 고정된 크기와 용량으로 인해 ensureCapacity() 메서드를 사용하여 최대 요소 수를 확장합니다.
사용자 정의 데이터 구조에서 iterator() 메서드를 호출할 때마다 Iterator 의 새 인스턴스가 생성 됩니다. 반복자가 현재 반복 상태를 유지하는 역할을 하므로 새 인스턴스를 만듭니다.
iterator() 메서드 의 구체적인 구현을 제공함으로써 향상된 for 문을 사용하여 구현된 클래스의 개체를 반복할 수 있습니다.
이제 사용자 정의 반복자를 나타내는 ShoppingCart 클래스 내부에 내부 클래스를 생성해 보겠습니다 .
public class ShoppingCartIterator implements Iterator<E> {
int cursor;
int lastReturned = -1;
public boolean hasNext() {
return cursor != size;
}
public E next() {
return getNextElement();
}
private E getNextElement() {
int current = cursor;
exist(current);
E[] elements = ShoppingCart.this.elementData;
validate(elements, current);
cursor = current + 1;
lastReturned = current;
return elements[lastReturned];
}
}
마지막으로 iterable 클래스의 인스턴스를 만들고 향상된 for 루프에서 사용하겠습니다.
ShoppingCart<Product> shoppingCart = new ShoppingCart<>();
shoppingCart.add(new Product("Tuna", 42));
shoppingCart.add(new Product("Eggplant", 65));
shoppingCart.add(new Product("Salad", 45));
shoppingCart.add(new Product("Banana", 29));
for (Product product : shoppingCart) {
System.out.println(product.getName());
}
3. 반복자 인터페이스
Iterator 는 Java Collections Framework의 멤버입니다. java.util 패키지에 속합니다이 인터페이스를 사용하면 반복 중에 컬렉션에서 요소를 검색하거나 제거할 수 있습니다.
또한 데이터 구조를 반복하고 해당 요소를 검색하는 데 도움이 되는 두 가지 메서드 ( next( ) 및 hasNext() ) 가 있습니다.
또한 Iterator 가 가리키는 현재 요소를 제거 하는 remove() 메서드가 있습니다.
마지막으로 forEachRemaining(Consumer<? super E> action) 메서드는 데이터 구조 내부의 나머지 각 요소에 대해 지정된 작업을 수행합니다.
3.1. 컬렉션 반복
정수 요소 List 을 반복하는 방법을 살펴보겠습니다 . 예제에서는 while 루프와 hasNext() 및 next () 메서드를 결합합니다 .
List 인터페이스는 Collection 의 일부 이므로 Iterable 인터페이스를 확장합니다. 컬렉션에서 반복자를 가져오려면 iterator() 메서드를 호출하기만 하면 됩니다.
List<Integer> numbers = new ArrayList<>();
numbers.add(10);
numbers.add(20);
numbers.add(30);
numbers.add(40);
Iterator<Integer> iterator = numbers.iterator();
또한 hasNext() 메서드 를 호출하여 반복자에 남아 있는 요소가 있는지 확인할 수 있습니다 . 그런 다음 next() 메서드 를 호출하여 요소를 가져올 수 있습니다 .
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
next() 메서드 는 반복에서 다음 요소를 반환합니다. 반면에 해당 요소가 없으면 NoSuchElementException 을 발생 시킵니다.
3.2. 반복자 인터페이스 구현
이제 Iterator 인터페이스를 구현할 것입니다. 사용자 지정 구현은 조건부 요소 검색을 사용하여 컬렉션을 반복해야 할 때 유용할 수 있습니다. 예를 들어 홀수 또는 짝수를 반복하기 위해 사용자 정의 반복자를 사용할 수 있습니다.
설명 을 위해 주어진 컬렉션에서 소수 를 반복할 것 입니다. 우리가 알다시피, 숫자는 1과 그 자체로만 나눌 수 있는 경우 소수로 간주됩니다.
먼저 숫자 요소 컬렉션을 포함하는 클래스를 생성해 보겠습니다.
class Numbers {
private static final List<Integer> NUMBER_LIST =
Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
}
또한 Iterator 인터페이스의 구체적인 구현을 정의해 보겠습니다.
private static class PrimeIterator implements Iterator<Integer> {
private int cursor;
@Override
public Integer next() {
exist(cursor);
return NUMBER_LIST.get(cursor++);
}
@Override
public boolean hasNext() {
if (cursor > NUMBER_LIST.size()) {
return false;
}
for (int i = cursor; i < NUMBER_LIST.size(); i++) {
if (isPrime(NUMBER_LIST.get(i))) {
cursor = i;
return true;
}
}
return false;
}
}
구체적인 구현은 일반적으로 내부 클래스로 생성됩니다. 또한 현재 반복 상태를 유지할 책임이 있습니다. 위의 예에서는 다음 소수의 현재 위치를 인스턴스 변수에 저장했습니다. next() 메서드 를 호출할 때마다 변수에는 다가오는 소수의 인덱스가 포함됩니다.
더 이상 남아 있는 요소가 없을 때 next() 메서드 의 모든 구현은 NoSuchElementException 예외를 발생시켜야 합니다. 그렇지 않으면 반복으로 인해 예기치 않은 동작이 발생할 수 있습니다.
PrimeIterator 클래스 의 새 인스턴스를 반환하는 Number 클래스 내부의 메서드를 정의해 보겠습니다 .
public static Iterator<Integer> iterator() {
return new PrimeIterator();
}
마지막으로 while 문 내에서 사용자 지정 반복자를 사용할 수 있습니다.
Iterator<Integer> iterator = Numbers.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
4. Iterable 과 Iterator 의 차이점
요약하면 다음 표는 Iterable 과 Iterator 인터페이스 간의 주요 차이점을 보여줍니다 .
반복 가능 | 반복자 |
---|---|
for -each 루프 를 사용하여 반복할 수 있는 컬렉션을 나타 냅니다. | 컬렉션을 반복하는 데 사용할 수 있는 인터페이스를 나타냅니다. |
Iterable 을 구현할 때 iterator() 메서드 를 재정의해야 합니다. | Iterator 를 구현할 때 hasNext() 및 next() 메서드 를 재정의해야 합니다. |
반복 상태를 저장하지 않습니다. | 반복 상태를 저장합니다. |
반복 중에 요소를 제거하는 것은 허용되지 않습니다. | 반복 중 요소 제거가 허용됩니다. |
5. 결론
이 기사에서는 Java 의 Iterable 인터페이스 와 Iterator 인터페이스 의 차이점과 사용법에 대해 살펴보았습니다 .
항상 그렇듯이 예제의 소스 코드는 GitHub에서 사용할 수 있습니다 .