IT_Programming/Java

클래스에서 enhanced For-Loop 사용

JJun ™ 2008. 1. 24. 21:24
LONG
 
// Does not compile
import!! java.util.*;
public class BadColony {
  static class Penguin {
    String name;
    Penguin(String name) {
      this.name = name;
    }
    public String toString() {
      return "Penguin{" + name + "}";
    }
  }

  Set<Penguin> set = new HashSet<Penguin>();

  public void addPenguin(Penguin p) {
    set.add(p);
  }

  public Iterator<Penguin> getPenguins() {
    return set.iterator();
  }

  public static void main(String args[]) {
    Colony colony = new Colony();
    Penguin opus = new Penguin("Opus");
    Penguin chilly = new Penguin("Chilly Willy");
    Penguin mumble = new Penguin("Mumble");
    Penguin emperor = new Penguin("Emperor");
    colony.addPenguin(opus);
    colony.addPenguin(chilly);
    colony.addPenguin(mumble);
    colony.addPenguin(emperor);
    Iterator<Penguin> it = colony.getPenguins();
// The bad line of code:
    for (Penguin p : it) {
      System.out.println(p);
    }
  }
}


enhanced for-loop로 Iterator를 전달할 수 없다. 다음 중 두 번째 라인은 컴파일 오류를 발생시킨다.

Iterator<Penguin> it = colony.getPenguins();
    for (Penguin p : it) {


오류:

BadColony.java:36: foreach not applicable to expression!! type
    for (Penguin p : it) {
                     ^

1 error


enhanced for-loop와 함께 클래스를 사용하려면 Iterator가 필요하지만 IteratorIterable 인터페이스를 통해 제공되어야 한다.

public interface java.lang.Iterable {
    public java.util.Iterator iterator();
}

사실 더 정확성을 기하기 위해서는, 기존의 일반 Object 대신 generic T를 사용함으로써 enhanced for-loop가 유형 변환을 방지하고 지정된 generic 형식을 반환하게 할 수 있다.

public interface java.lang.Iterable<T> {
    public java.util.Iterator<T> iterator();
}

그런 다음 이 Iterable 개체가 enhanced for-loop에 제공된다. Colony 클래스가 Iterable를 구현하고 그 새로운 iterator() 메소드가 getPenguins()에서 제공하는 Iterator를 반환하게 함으로써 enhanced for-loop를 사용하여 Colony의 Penguin을 루프할 수 있게 된다.

다음과 같이 알맞은 implements 절을 제공함으로써

public class Colony implements Iterable<Colony.Penguin> {

Colony,에 대해 enhanced for-loop를 얻게 된다.

for (Penguin p : colony) {


코드가 수정되어 업데이트된 Colony 클래스는 다음과 같다.

import!! java.util.*;

public class Colony implements Iterable<Colony.Penguin> {

  static class Penguin {
    String name;
    Penguin(String name) {
      this.name = name;
    }
    public String toString() {
      return "Penguin{" + name + "}";
    }
  }

  Set<Penguin> set = new HashSet<Penguin>();

  public void addPenguin(Penguin p) {
    set.add(p);
  }

  public Iterator<Penguin> getPenguins() {
    return set.iterator();
  }

  public Iterator<Penguin> iterator() {
    return getPenguins();
  }

  public static void main(String args[]) {
    Colony colony = new Colony();
    Penguin opus = new Penguin("Opus");
    Penguin chilly = new Penguin("Chilly Willy");
    Penguin mumble = new Penguin("Mumble");
    Penguin emperor = new Penguin("Emperor");
    colony.addPenguin(opus);
    colony.addPenguin(chilly);
    colony.addPenguin(mumble);
    colony.addPenguin(emperor);
    for (Penguin p : colony) {
      System.out.println(p);
    }
  }
}

이 코드를 실행하면 다음과 같은 출력이 생성된다.

> java Colony

  Penguin{Chilly Willy}
  Penguin{Mumble}
  Penguin{Opus}
  Penguin{Emperor}


 

개별 Penguin은 내부적으로 Set 형식 컬렉션에 보존되므로 반환된 순서가 삽입 순서와 반드시 일치하지는 않는데, 이번 경우에는 일치한다.

단순히 "implements Iterable"이라고 하지 않고 반드시 "implements Iterable<T>" 클래스의 implements 절을 generic화해야 한다. 그렇지 않으면 enhanced for-loop는 요소별로 Object만 반환할 것이다.

enhanced for-loop에 대한 자세한 내용은 JDK 1.5의 Java 프로그래밍 언어 안내서를 참조한다.

ARTICLE 이 아티클의 영문 원본은
http://java.sun.com/mailers/techtips/corejava/2007/tt0907.html#1
에서 볼수 있습니다.

이 팁은 Java SE 6을 사용하여 작성되었습니다. 이번 및 향후 테크팁을 사용하기 위해 Java Platform, Standard Edition 6 Development Kit(JDK 6)을 Java SE 다운로드 페이지에서 다운로드할 수 있습니다.

enhanced for-loop는 Java SE 플랫폼 버전 5.0에 도입되어 널리 쓰이는 기능 중 하나이다. 간단한 구조 덕분에 어레이/컬렉션의 한 요소에서 다른 요소로 이동하는 방법을 명시적으로 표현하지 않고서도 각 요소를 거치는 for-loop를 제공하여 코드를 간소화할 수 있다.

기존의 코딩 스타일은 새로운 for-loop 구문에 들어맞지 않기 때문에 어레이/컬렉션의 각 요소를 거치려면 enhanced for-loop를 사용해야 한다. 그러나 새로운 스타일을 적용할 경우 코드는 다음과 같은 형태에서

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

다음과 같은 형태로 바뀔 것이다.

for (String element : array) {
    System.out.println("Element: " + element);
}

"array"가 String 개체의 array로 정의되었다고 가정하면, array를 루프할 때 각 요소가 요소 변수에 할당된다. enhanced for-loop의 기본 사항은 이전 테크팁:
향상된 For Loop(2005년 7월 4일)를 참조한다.

Colony라는 클래스가 있고 이 클래스가 여러 Penguin 개체로 구성된 경우, enhanced for-loop를 작동하기 위한 추가적인 작업 없이 각 Penguin 요소를 루프하는 방법 중 하나는 Iterator를 반환하고 Colony를 반복하는 것이다. 하지만 enhanced for-loop는 Iterator와 작동하지 않으므로 다음은 컴파일조차 되지 않는다.