ページ

2014年10月21日

Javaとか

原稿の残りの部分。

コレクションAPI

Iterableインタフェースを実装してみよう

前節でIterableインタフェースを実装したオブジェクトであれば拡張forループで回すことができると書きました。つまり、自作のクラスでもIterableインタフェースを実装していれば、拡張forループに対応できます。
例えば、リストの要素をループで回すとき、一緒にインデックス番号を取得して処理したいケースがあります。インデックスアクセスをする場合は、次のように記述します。
List list = Arrays.asList("foo", "bar", "buzz");
for (int i=0; i
このコードを拡張forループで記述すると次のようになります。
List list = Arrays.asList("foo", "bar", "buzz");
int index=0;  // (1)
for (String str: list) {
    System.out.println(index + " " + str);
    index++; // (2)
}
(1)でインデックス番号を保持する変数を宣言して、(2)でインデックス番号をインクリメントしています。せっかく、拡張forループで簡潔に記 述できるようになったのに、インデックスでのアクセスのようにインデックス番号をまた管理しなければならないのは煩雑です。イテレータでループするとき に、インデックス番号も合わせて管理できれば便利じゃないですか?
ここでは、インデックス番号とリストの要素を管理できるイテレータを作ってみましょう。利用方法は次のようになります。
List list = Arrays.asList("foo", "bar", "buzz");
for (CollectionUtils.Entry entry: CollectionUtils.enumurate(list)) { // (1)
    System.out.println(entry.getIndex() + " " + entry.getValue()); // (2)
}
今回はCollectionUtilsというクラスを作成します。(1)のようにCollectionUtilsのenumurateメソッドに Iterableなオブジェクトを渡すと、インデックス番号と要素を管理するIterableなオブジェクトを返します。このIterableなオブジェ クトは、CollectionUtils.Entryオブジェクトを保持します。(2)ではentryからインデックス番号と要素の値を取り出して出力し ています。
それでは、ちょっと長いですが、このCollectonUtilsを実装したクラスが次のコードです。
import java.util.*;

public class CollectionUtil {
    // (1) Entryクラス宣言
    public static class Entry {
        int index;
        T value;
        Entry(int index, T value) {
            this.index = index;
            this.value = value;
        }

    public int getIndex() { return index; }
    public T getValue() { return value; }
     }

    // (2) enumurateメソッド
    public static  Iterable> enumurate(Iterable iterable) {
        final Iterator iter = iterable.iterator(); // (3)
        return new Iterable>() {  // (4)
            @Override
            public Iterator> iterator() { // (5)
                return new Iterator>() { // (6)
                    int index = 0; // (7)
                    @Override
                    public boolean hasNext() {  //(8)
                        return iter.hasNext();
                    }
            
                    @Override
                    public void remove() { // (9)
                        iter.remove();
                    }

                    @Override
                    public Entry next() { // (10)
                        return new  Entry(index++, iter.next());
                    } 
                };
            }
        };
}
(1)はEntryクラスの実装です。Entryクラスはインデックス番号(index)と値(value)を保持するバリューオブジェクトです。 (2)はIterableなオブジェクトを返すenumurateメソッドです。引数にはIterableなオブジェクトを受け取ります。上の例では Listオブジェクトを指定しましたが、イテレーション可能なオブジェクトであればすべて、インデックス番号付きのイテレータに変換できます。 (3)では、引数で受け取ったIterableなオブジェクトからイテレータを取得しています。(4)では、新たに新しいIterableなオブジェクト を返しています。ここでは、無名クラスとしてIterableなオブジェクトを宣言しています。
IterableインターフェースはIterator> iterator()を実装します(5)。このメソッドはIteratorを返すメソッドです。(6)でIteratorオブジェクトを無名クラスとして 宣言して返しています。この無名クラスは、内部データとしてインデックス番号を保持して(7)、enumurateメソッド内で宣言したiter変数 (Iteratorオブジェクト)を参照します。引数で渡されたイテレータと、新たに作成したイテレータの2つを同時に扱うので、少し複雑ですね。 Iteratorインターフェースは、hasNext, remove, nextの3つのメソッドを実装する必要があります((8),(9)(10))。(8)はhasNextを、(9)はremoveメソッドを実装していま す。それぞれ、(3)で設定したiter変数のhasNextとremoveメソッドを呼び出しているだけです。 (10)のnextメソッドでは、次のイテレータの要素として(1)で宣言したEntryをインデックスとオリジナルのイテレータの値 (iter.next())でインスタンス化して返しています。
これでインデックス番号と値を同時に管理できる汎用的なイテレータを利用できるようになりました。


例外処理

プログラムの実行中に異常事態が発生した場合に、Javaでは例外オブジェクトをメソッドの呼び出し元に送出します。例外オブジェクトはすべて、 Throwableクラスを継承したオブジェクトです。Throwableオブジェクトをthrow文で投げることによって、呼び出し元でエラー処理でき ます。
Throwable
  +- Exception
        +- RuntimeException
        +- RuntimeException以外の例外クラス
  +- Error
例外は実行時例外と検査例外の2つに分類されます。実行時例外は、RuntimeExceptionクラスとErrorクラス、また、それらの派生 クラスです。 Errorクラスとその派生クラスは、メモリ不足の時に発生するOutOfMemoryErrorなどJavaのVMが発生させるエラーです。深刻なエ ラーのため、通常はこのエラーはキャッチすべきではありません。 RuntimeExceptionは、配列で範囲外のインデックス値を指定した時に発生するIndexOutOfBoundsExceptionやメソッ ド呼び出しで変数がnull参照している時に発生するNullPointerExceptionなど、アプリケーションの通常の処理で発生する例外です。 この種の例外は通常はプログラム中で事前に値の検証を行って、例外を発生させないのが良いとされています。 これら2種類の実行時例外は、次に説明する検査例外と違いメソッドが送出する例外をメソッドシグネチャに含める必要はありません。
検査例外は次のようにメソッドシグネチャにthrowsに続けて呼び出し元に送出できる例外を指定します。呼び出し元では、try ... catch説で送出された例外を捕捉するか、さらにその呼び出し元に例外を送出する必要があります。
public void method() throws 例外1, 例外2 {
実行時例外と検査例外の使い分けとして、Effective Javaでは「 回復可能な条件にはチェック例外を、プログラミング・エラーにはランタイム例外を使う」と規定しています。しかし、最近は検査例外の弊害として
  • チェック例外が、実装の詳細を不用意にさらけ出している
  • 不安定なメソッド・シグニチャー
  • 読みとれないコード
  • 例外の飲み込み
  • 例外ラッピングが多すぎる
と批判して実行時例外を推奨しているフレームワークも存在します。例外についての議論はdeveloperWorksの「Javaの理論と実践: 例外をめぐる議論」( http://www.ibm.com/developerworks/jp/java/library/j-jtp05254/ )で詳しく議論されています。

try ... catch節

Javaの例外の補足はtry ... catch節を使います。catchブロックは次のように複数記述して、複数の例外を捕捉できます。finallyブロックは、例外が発生してもしなくても、常に実行されます。
少し長くなりますが、次のコードは例外補足のサンプルです。(2)のメソッドthrowExceptionでは、引数lineが文字 列"exception"の場合に、(1)で定義した例外MyExceptionを送出しています。(3)のmainメソッドの中で、ファイル in.txtを開いて((4))、(5)で一行ごとに読み込んでいます。この時、例外IOExceptionが発生する可能性があるため、(7)で補足し ています。また、このwhileループの中で(2)のthrowExceptionメソッドを呼び出しているので、例外MyExceptionが発生する 可能性があります。そのため、(8)で例外MyExceptionを補足しています。 (4)でReaderを開いているため、後片付けとして開いたreaderオブジェクトを閉じる必要があります。IOExceptionや MyExceptionが発生しても、開いたreaderオブジェクトはcloseする必要があるため、(9)のfinallyブロックでreaderオ ブジェクトのcloseメソッドを呼び出して、閉じます((10))。
import java.util.*;
import java.io.*;
  
    
public class MyTest {
    // (1)
    static class MyException extends Exception {}

    // (2)
    static void throwException(String line) throws MyException {
        if (line.equals("exception")) {
            throw new MyException();
        }
    }

    // (3)
    public static void main(String[] argv) {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader("in.txt")); // (4)
            String line;
            while ((line = reader.readLine()) != null ) { // (5)
                System.out.println(line);
                throwException(line); // (6)
            }
        } catch (IOException e) { // (7)
            e.printStackTrace();
        } catch (MyException e) { // (8)
            e.printStackTrace();
        } finally {  // (9)
            if (reader != null) {
                try {
                    reader.close(); // (10)
                } catch (IOException e) {
                }
            }
        }
    }
}
もう一度上のコードを見てくだだい。(7)と(8)の例外発生時のコードは、スタックトレースを出力するだけの全く同じコードです。実際のアプリ ケーションでも、複数の例外の対応で同じ処理をすることも多いです。Java8では、例外クラスを|でつなげることで、複数の例外をまとめて一つの catchブロックで捕捉できます。上のmainメエソッドの例外処理をJava8の記法で記述すると次のようになります(1)。
public static void main(String[] argv) {
    BufferedReader reader = null;
    try {
        : 省略
        }
    } catch (IOException | MyException e) { // (1)
        e.printStackTrace();
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
            }
        }
    }
}

try-with-resources文

前節のBufferedReaderのように、後処理として必ず閉じる必要があるオブジェクトがあります。そのため、finallyブロックで常に オブジェクトのnullチェックを行って、closeメソッドを呼び出すことは煩雑で、しばしば閉じ忘れが発生します。Java7からはtry- with-resources文が導入され、閉じ忘れが発生しないようになりました。
前節のサンプルコードをtry-with-resources文を使って書き換えてみましょう。
public static void main(String[] argv) {
    try (BufferedReader reader = new BufferedReader(new FileReader("in.txt"))){ // (1)
        String line;
        while ((line = reader.readLine()) != null ) {
            System.out.println(line);
            throwException(line);
        }
    } catch (IOException | MyException e) { // (2)
        e.printStackTrace();
    }
        }
    }
}
以前のコードではBufferedReaderの宣言がtry文の外にあり、変数のスコープが大きくなっていました。try-with- resources文を使うことで、BufferedReaderのスコープがtryブロックの中に限定され、コードがシンプルになります。 (1)はtry-with-resources文です。try-with-resources文では、tryのあとの()内で閉じる必要のあるオブジェク トを作成します。ここで作成したオブジェクトは、tryブロックを抜ける時に自動でcloseメソッドが呼ばれます。このため、前節のような finallyブロックが不要になります。 (2)では、catchブロックで通常のtryブロックの中で発生する例外を補足して処理できます。
上の例ではtry-with-resources文の中で、自動的に閉じられるオブジェクトはひとつだけです。次の例のように、複数個のオブジェクトを自動で閉じる場合は、「;」で連結して記述します((1))。
public static void main(String[] argv) {
    // (1)
    try (
        BufferedReader reader = new BufferedReader(new FileReader("in.txt"));
        BufferedWriter writer = new BufferedWriter(new FileWriter("out.txt"))
      ) {
        String line;
        while ((line = reader.readLine()) != null ) {
            writer.write(line);
            writer.newLine();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

AutoCloseableインタフェース

try-with-resources文のリソースとして使用できるクラスは、java.io.AutoCloseableインターフェースを実装 したクラスです。前節のBufferedReaderやBufferedWriterは、AutoCloseableインターフェースのサブインタフェー スのCloseableを実装しています。
AutoCloseable(または、Closeable)インタフェースは、次のcloseメソッドがひとつだけ定義されています。
  void close throws IOException
それでは、ストリームから一行ごとに読み込んで、各行を「,」で分割した文字列の配列を管理するCsvReaderクラスを作ってみましょう。 (1)は、CsvReaderのコンストラクタです。コンストラクタの中でBufferedReaderオブジェクトを作成しています。(2)の readLineメソッでは一行読み込んで、「,」で分割しています。(3)は、AutoCloseableのcloseメソッドの実装です。このメソッ ドでは、(1)で作成したBufferedReaderオブジェクトのcloseメソッドを読み込んでいます。
public class CsvReader implements AutoCloseable {
    private BufferedReader reader;
    public CsvReader(Reader reader) { // (1)
        this.reader = new BufferedReader(reader);
    }
    public String[] readLine() { // (2)
        String line = reader.readLine();
        return line.split(",");
    }

    @Override
    public void close() throws IOException { // (3)
        System.out.println("closing...");
        reader.close();
    }
}
次のコードは、このクラスを実際に使用しています。AutoCloseableインタフェースを実装しているので、tryブロックを抜けるときに自動的にCsvReaderのcloseが呼ばれます。
try (CsvReader csv = new CsvReader(new FileReader("test.csv"))) {
    String[] fields;
    while ((fields = csv.readLine()) != null) {
        System.out.println(fields);
    }
}

クラス定義

初期のJavaではクラスの定義は、一つのソースファイルに一つのクラスしか作成できませんでした。現在でもpublicなトップレベルクラスにはその制約はありますが、内部クラスやプライベートなクラスは、一つのソースファイルに複数記述できます。

パッケージスコープのトップレベルクラス

次の例のように、一つのソースコードPublicClass.javaファイルに、publicなクラスPublicClassとパッケージスコー プのクラスPrivateClassの2つのクラスを定義できます。パッケージスコープのクラスは、この複数定義できます。このファイルをコンパイルする と、PrivateClass.classとPublicClass.classの2つのクラスファイルが生成されます。つまり、 PublicClass.javaと一緒にPrivateClass.javaファイルで別途PrivateClassクラスを定義できません。
```java:プライベートなトップレベルクラス(PublicClass.java) class PrivateClass { // (1) }
public class PublicClass { // (2) } ```

ネストしたクラス

クラスの中にさらにクラスを定義できます。クラスの中のクラスを、ネストしたクラスと呼びます。次のコードはネストしたクラスを定義しています。 (1)はトップレベルのクラスOuterで、(2)のInnerクラスがネストしたクラスになります。ネストしたクラスは、ここではpublicスコープ ですが、スコープの範囲に応じて、privateスコープやパッケージスコープやprotectedスコープで定義できます。ネストしたクラスではクラス にstaticをつけます。staticをつける理由は、次の内部クラスで説明します。 このクラスをコンパイルすると、Outer.classとOuter$Inner.classの2つが生成されます。
public class Outer { // (1)
    public static class Inner { // (2)
    }
}

内部クラス

内部クラスは、ネストしたクラスと同様に、クラスの中にクラスを定義できます。しかし、ネストしたクラスと違い、内部クラスは外部クラスのインスタ ンスに紐付いています。ネストしたクラスを利用する場合は、new Outer.Inner()としてインスタンス化できますが、内部クラスでは外部クラスをインスタンス化して、そのインスタンスから内部クラスをインスタ ンス化します。
次のコードは内部クラスの例です。(2)で内部クラスを定義しています。内部クラスはネストしたクラスと違い、staticは付けないこと注意して ください。(3)は、内部クラスInnerのオブジェクトから、外部クラスのオブジェクトのフィールドにアクセスしています。これはネストしたクラスと違 い、外部クラスのオブジェクトに紐付けられているために可能になります。ここでは直接変数を指定していますが、外部クラスの変数を明示するために Outer.this.strと指定することもできます。 (4)では、外部クラスのメソッドから内部クラスをインスタンス化しています。 このファイルをコンパイルするとOuter.classとOuter$Inner.classの2つのファイルが生成されます。
public class Outer {
    private String str = "outer value"; // (1)
    public class Inner { // (2)
        public void print() { // (3)
            System.out.println(str);
        }
    }
    public void method() {
        Inner inner = new Inner(); // (4)
    }
}

ローカルクラス

クラスの中にクラスを定義できたように、メソッドの中にもクラスを定義できます。メソッドの中に定義したクラスは、クラスを定義したスコープに依存 します。 次のコードは、メソッドの中にローカルクラスを定義しています。(1)と(4)は実際にローカルクラスLocalClassを定義しています。同じ名前の クラスですが、それぞれ別のクラスとして認識されます。このファイルコンパイルすると、Outer.classと Outer$1LocalClass.classとOuter$2LocalClass.classの3つができていることからも、それらは別のクラスだ とわかります。(2)と(6)では、それぞれ(1)と(3)で定義したクラスをインスタンス化しています。 ローカルクラスからは、メソッド内で定義した変数にアクセスできます。アクセスできるのはfinal定義された変数だけです。そのため、メソッド内の変数 の値を変更することはできません。(5)のLocalClassのprintメソッドでは、メソッドのfinalで定義されたstr変数にアクセスしてい ます。final指定されていない変数にアクセスしようとすると、コンパイルエラーが発生します。
public class Outer {
    public void method1() {
        class LocalClass {}; // (1)
        LocalClass lc = new LocalClass() // (2)
    }
    public void method2() {
        final String str = "method2"; // (3)
        class LocalClass { // (4)
            public void print() { // (5)
                System.out.println(str);
            }
        }
        LocalClass lc = new LocalClass(); // (6)
        lc.print();
    }
}

無名クラス

無名クラスは匿名クラスとも呼ばれています。無名クラスは、インターフェースや抽象クラスを利用するときに、名前やクラス定義をせずに直接インスタ ンス化して、その実装を書くものです。メソッド内や、クラスフィールドのインスタンス化時に利用します。名前付きのクラスと違い、クラスのインスタンス化 を一箇所からしか行わない場合に無名クラスを利用することが多いです。 無名クラスもローカルクラスと同様にfinalで定義された外部の変数にアクセスできます。
次のコードは、java.lang.Runnableを無名クラスでインスタンス化したものです。(1)でRunnableインタフェースをインス タンス化しています。new Runnable()に続いて{}のブロック内で、Runnableインタフェースが持つrunメソッドを実装しています(3)。無名クラスはコンストラ クタを持てませんが、フィールドに初期値を設定できます(2)。また、ローカルクラスと同様に、finalで定義された変数にはアクセスできます。 (4)の(1)から始まった{}ブロックの最後に「;」を忘れないでください。
Runnable runnable = new Runnable() { // (1)
    String str = "running"; // (2)
    @Override
    public void run() { // (3)
        System.out.println(str);
    }
}; // (4)
new Thread(runnable).start();

可変長引数

可変長引数は、引数の数を複数指定でき、実際の引数の数はその呼び出し元によってきまります。

基本的な利用例

java.lang.Stringクラスのformatメソッドではpublic String format(String fmt, Object... args)のように定義されています。可変長引数は、引数の型宣言のあとに「...」を追加します。可変長引数を指定できるのは、一番最後の引数だけで す。 Stringクラスのformatメソッドは次のように利用します。
str = String.format("out: nothing"); // (1) "out: nothing"と出力
str = String.format("out: %d", 1); // (2) "out: 1"と出力
str = String.format("out: %d %s", 1, "foo"); // (3) "out: 1 foo"と出力
(1)はフォーマット用の文字列だけとり、可変長引数を取らないケースです。(2)は可変長引数に「1」を指定しています。(3)は可変長引数とし て「1」と「foo」の2つを指定しています。引数の数に関わらず、呼び出されるformatメソッドはひとつだけで、オーバロードされていません。

メソッドから使用例

可変長引数はメソッド内では配列として扱います。次のコードは可変長引数を出力するメソッドです。 (1)でargvを可変長引数としてとります。(2)で可変長引数を直接出力しています。[Ljava.lang.String;@15db9742のよ うに出力されます。これはargvがStringの配列を意味しています。(3)は可変長引数を拡張forループで回して、内容を出力しています。
public void print(String... argv) { // (1)
    System.out.println(argv); // (2)
    for (String s: argv) { // (3)
        System.out.println(s);
    }
}
上のメソッドは、メソッドシグネチャがpublic void print(String[] argv)とほぼ、同義です。しかし、配列で指定した場合は、argvがnullのケースがありますが、可変長引数では、必ず非null値になります。つ まり、引数に何も指定されない場合は、空の配列になります。

配列として呼び出し例

このメソッドを利用するときは、通常はprint("foo", "bar", "buzz");のように利用します。 さて、可変長引数はメソッド内で配列として扱われます。実はメソッドの呼び出し元からも配列として扱うこともできます。次の例は、可変長引数に配列として 値を指定しています。これは、print("foo", "bar", "buzz");と同義です。
String[] argv = new String[]{"foo", "bar", "buzz"};
print(argv);
ただし、配列として値を渡す場合、print((String[])null);のように配列として明示的にnullを渡すと、printメソッド の可変長引数argv自体もnullになるので気をつけてください。print(null)の場合は、可変長引数(配列)の最初の値がnullになり、配 列自体は実体があります。

2014年8月20日

保土ヶ谷のジムとか

ほっといたら、だんだん書かなくなるので…

で、平塚から横浜の保土ヶ谷に引っ越して数カ月がたちました。平塚にいたころは、セントラルのフィットネスクラブか市のトレーニングルームに行っていました。まあ、市のトレーニングルームはちょっと遠かったので、セントラルが休みの時とか、数えるほどしか行ってませんが…

で、保土ヶ谷に引っ越して、近くにジムはいくつかあります。健康保険の福利厚生で利用できるのは天王町のコナミです。でも、ここ、狭い!まあ、狭いのはいいです。マシンが古い。使えなくもないのですが、狭い上にボロっちいマシンだとモチベーションが上がらないし、なんだか、筋トレコーナーが済に追いやられている感じがしてちょっと・・・。でも、スタッフのおねーさんは可愛かった。でも、一回行っただけで行くのをやめました。横浜のコナミは高いので無理です。

そのあと、保土ヶ谷区のスポーツセンター(横浜市のやつ)にしばらく、行っていました。一回300円でリーズナブルですが、それなりに混んでいます。 トレッドミルは結構使われていて、空くのをじっと待つのです。フリーウェイトのコーナーは強うそうな人たちが独占してます。あんなところ、怖くて入っていけません。まあ、そもそも、フリーウェイトのコーナーに入るには講習を受けないと行けないらしいですが、めんどくさくて受けてません。なので、あそこに入る資格すらありません。マシンは去年、入れ替えたばかりなので、どれも新しくて綺麗です。

で、そんなこんなで、もうちょっとジムにちゃんと行きたいな〜、って思って、駅ビルにあるJexerに行ったんですよ。見学に行った時、潰れるんじゃないかってぐらい、空いてるんです。いいですね。基本的に空いていて、混む時間帯でもそれなりみたいです。経営する方は大変かもしれませんが、利用する方はいいですね。2ヶ月ちょっと通っていますが、ほとんど順番待ちをすることがないです。有酸素系は全く待たないです。利用人数に対して有酸素マシンの数が多すぎます(笑)。

でも、ちょっと狭い。でも、狭すぎることはないです。で、筋トレと有酸素運動しかできません。プールはないし、スタジオもないです。プールもスタジオもどちらも使わないので、それらがない分、安いのはいいです。えーと、月5000円ぐらいです。あと、サウナは欲しい…。かも。

でもって、スタッフの人も暇なのか、いろいろ話しかけて来てくれるので、いい感じです。いや、最初は黙々とやれればいいと思っていたので、うっとおしかったです。でも、フォームがおかしかったらこちらから言わなくても教えてくれるし、何かを発見しても教えてくれるし、いい感じです。ただ、他の人に教えているのを見ていると、他の人には最初は軽い重量で教えているのに、僕には普通の重量を与えられます。

で、全体的に空いていて、フリーウェイトのところにも、とっても強うそうな人はいません。平塚のジムはバーベルに人がいると数十分ぐらい専有し続けていました、ここはそんなに長時間専有し続ける人がいないです。まあ、フリーウェイトはちょっと混み気味と時もありますが、そんな時も少し待てば使えます。

それと、スタッフの人は休憩時間とか仕事が終わったら、一緒にトレーニングしています。いいですね。

あっ、あと、このジム、社員のひとは人の名前をちゃんと覚えています。バイトの人はよくわからないですが・・・。普通に○○さん、って呼びかけてきます。
あと、3日行かないと、「久しぶりですね」って言われます…。

2014年4月1日

拡張forループでループの回数も同時に欲しいよね、でこんなふうに書いた

昨日のアリエルであったJava8の勉強会で、iteratorをそのままstreamに流せないと初めて知って、いささかめんどくさい感があったりもしますが、世の中、そんなものです。あったかくなってきたとか、朝が夜ではなく朝になってきたとか、桜が咲いたとか、浮かれている場合ではありません。

前回、iterator自分で書いてみない?ってことで、だれも書いてくれなくってとても残念です。なので、自分で書いてみました。

import java.util.*;

public class CollectionUtil {
    public static class Entry<T> {
         int index;
         T value;
         Entry(int index, T value) {
             this.index = index;
             this.value = value;
         }

         public int getIndex() { return index; }
         public T getValue() { return value; }

    }

    public static <T> Iterable<Entry<T>> enumurate(Iterable<T> iterable) {
        final Iterator<T> iter = iterable.iterator();
        return new Iterable<Entry<T>>() {
            public Iterator<Entry<T>> iterator() {
                return new Iterator<Entry<T>>() {
                    int index = 0;
                    public boolean hasNext() {
                        return iter.hasNext();
                    }
           
                    public void remove() {
                        iter.remove();
                    }

                    public Entry<T> next() {
                        return new  Entry<T>(index++, iter.next());
                    }
                };
            }
        };
    }


    public static void main(String[] argv) {
        List<String> l = new ArrayList<String>();
        l.add("hoge");
        l.add("fuga");
        for (Entry<String> entry: CollectionUtil.<String>enumurate(l)) {
             int index = entry.getIndex();
             String v = entry.getValue();
             System.out.println(index + " " + v);
        }
    }
}

色がついていないと、ちょっと読みにくいですね。IDEにでも貼り付けて、綺麗にしてください。

で、僕はPythonista(Pythonを使う人)だったらしいので、enumurateってメソッドを作ってあげて、その人がiterableのオブジェクトを返すことにしてあげました。やっていることは基本的には同じです。なんとかクラスを実装してください、って課題なのに、設問をいきなり無視しています。年寄りはそんなものです。我慢してください。

この手のメソッドを作るときによくやるのが、引数とかで本当の具象クラスを指定することはさすがにないと思いますが、ListやCollectionを指定しちゃうことが多いです。enumurateの中身は引数からiteratorが取れればいいだけなので、Itarableインターフェースを指定します。曖昧にできるところはなるべく曖昧にしておいたほうが、メソッドがいろいろ使いまわせてよいのです。



無名クラス、いっぱい。なぜ、無名クラスにしたのかって言うと、クラス名を何にするか決められなったからです。

Iteratorは、Javaに限らず一般的なプログラミングの概念です。気になる人は、パーフェクトJavaの181ページを読んでください。あれ?無名クラスについては書いていない気がする。井上さん、追加してください。それから、マルチスレッド的なことも、Concurrentを追加してください。その代わりにGUIの部分はなくてもいいです。
それから、enumはやれば出来る子なので、もっと詳しくして欲しいです。