ページ

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はやれば出来る子なので、もっと詳しくして欲しいです。

DaoでのResultSetへのアクセスはenumでいいよね

Java8でラムダが使えれば…。
で、DaoでResultSetへのアクセスでインデックスでアクセスする場合、

int index=0;

dto.setX(resultSet.getInt(++index);
dto.setY(resultSet.getInt(++index);
dto.setZ(resultSet.getInt(++index);

ってアクセスさせるとメンテナンス性が落ちるよね、って話しでした。個人的にはカラムでのアクセスで問題ないと思っていますが、インデックスでのアクセスもenumでアクセスさせれば、もう少し、メンテナンス性が上がります。

こんなかんじですね。

enum ColumnName  {
    column1,
    column2,
    column3;

    public int getIndex() {
        return ordinal() + 1;
    }

    public static String getSelectStatement() {
        StringBuilder sb = new StringBuilder();
        for (String s: ColumnName.values()) {
            if (sb.length()>0) {
                 sb.append(",")
             }
             sb.append(s):
          }
     }
}


SQL文を組み立てるときは


    String sql = "SELECT " + ColumnName.getSelectStatetement() + " FROM SOME_TABLE"

ResultSetは、

    dto.setX(rs.getInt(ColumnName.column1));
    dto.setY(rs.getInt(ColumnName.column2));
    dto.setZ(rs.getInt(ColumnName.column3));

ほら。フィールドが追加されてもenumに値をセットするだけで、順番も意識しなくてよくなりました。

まあ、enumに値を追加することに神経を集中してdtoに詰めるのを忘れちゃいそうですね。

で、これがもう少しメンテナンス性は挙げられるようになる、と書いていた理由です。
ということで、技術は楽をするための道具です。言語に新しく追加されたものは、世界中の頭のいい人が、もっと楽をしたいと思って追加されるものです。なので、マゾな人以外は積極的に新しいものを使って、楽をできるところは楽をして、本質的に難しいところに開発者は専念すべきなのです。そのために、新しい技術を追い求めるのです。いやいや、それは嘘です。僕は新しいものが好きだから、追い求めるだけです。


それから、そのうち、リフレクションしたくなってくるかもしれません。でも、それすると、メンテナンス性が更に高まりますが、パフォーマンスは少し落ちます。我慢してください。その次がバイトコード生成ですが、そこまで行くと、もう、あちらの世界の住人になって、もう、戻ってこれません。気をつけてください。

追記
======

最近は朝、家を出る時が夜ではなく朝になってきて、ちょっと嬉しいです。

ということで、昨日の続き。昨日のように慌ただしいタイミングじゃないのでゆっくりと書けます。

まず、前提としてenumはやれば出来る子です。どこかでenumは所詮はクラスだよ、と書いたつもりですが、所詮はクラスなので、クラスでできることは大体出来ます。Effective Javaにはシングルトンもenumでできるよ、って書いていたように思いますが、僕は実際にやったことはないです。

さて、所詮はクラス、されどクラスなので、enumもinterfaceを身にまとってかっこ良く振る舞ってくれます。
例えばこんな感じ。

interface Ge {
    public void urya();
}

enum Ho implements Ho {
    H {
        public void urya() { System.out.println("Hoo"); }
    },
    G {
        public void urya() { System.out.println("Gee"); }
    }
}

で、 Ho.H.urya()って感じで使えます。なので、

for (Ho h: Ho.values) {
    h.urya();
}

で全部回りますね。


じゃあ、本題です。Daoでdtoにブツを詰め込むときに、場所が離れていると詰めるのを忘れがちになります。頑張ればHibernateがやっているようにもっとスマートにできなくもないですが、それならHibernate使えよ、ということになってしまいます。なので、現実的な妥協点は次のような感じ。
変数名とかメソッド名は割と適当なので、適当に置き換えてください。。


interface Binder {
    public void bind(int position, ResultSet rs, Dto dto);
}

enum Column implements Binder {
    FIELD_A {
        public void bind(int position, ResultSet rs, Dto dto) {
            dto.setField_A(rs.getInt(position + 1);
        }
     },
     FIELD_B {
        public void bind(int position, ResultSet rs, Dto dto) {
            dto.setField_B(rs.getString(position + 1);
        }
     };


     public String listFields() {
         StringBuilder sb = new StringBuilder();
         for (Column c: Column.values()) {
             if (sb.length() > 0) {
                 sb.append(",");
              }
              sb.append(c.name());
          }

           return sb.toString();
    }
}


で、もう一度、SQL文を組み立てるときは、

    String sql = "Select " + Column.listFields() + " From Some_table";

Dtoに値を放り込むときは、前回の記事で書いたIndexableIteratorがある前提で

    for (IndxableIterator.Pair<Column> pair: new IndexableIterator<Column>(Column.values())) {
        c.getValue().bind(c.getIndex(), resultSet, dto);
     }

ってやれば関連が強いものが近くに置かれて忘れ難くなった。フィールドが追加されたら、enumのところとdtoに追加すればいい。で、interfaceとenumはDTOの中にInner Classとして宣言すれば、関連性がより強くなって忘れにくい、変更箇所が局所化できますね。
それに、DAOの方はコードの変更が必要なくなるおまけ付き。

Java8のラムダとか、FunctionalInterafaceが入ってくると、各bindメソッドがラムダ式でもっと簡単に書けて、初期化の引数として渡せるので、かなりスッキリするはずです。


ということで、これくらいがJava7までの現実的な妥協点じゃないでしょうか?

最期におさらいをすると、enumはあなたが思っている以上にできる子なのです。

拡張forループでループの回数も同時に欲しいよね。

ちょっとだけ、拡張forで質問があったので、追加です。
前回の記事の中で次のように書いています。



> 拡張forループはいいのですが、今がコレクションの何番目か、ってのが取れたらもっと良かったのに…。

これは言語仕様としてはインデックスの位置が取れないと言うだけです。ちょっと別の言語で、goの場合は次のように書けてインデックスも同時に取得できます。便利ですね。

array := []string {"hoge", "fuga"}
for index, value := range array {
   // do something...
}

Javaのforループでは2つの値をとることができませんが、自前でイテレータを書くことができます


拡張forループで使えるようにするには、Iterableをimplementすればいいだけです。
で、こんな感じで使えるようになれば、まあ目的は達成できますね。

public class IndexableIterator<T> implements Iterable<T> {
   public static class Entry<T> {
        final int index;
        final T value;
        private Entry(int index, T value) {
            this.index = index;
            this.value = value;
        }
        public int getIndex() { return index; }
        public T getValue() { return value; }
    }


   // TODO: implement
}

というような感じで、IndexableIteratorを作って、実際に使う場面では

List<String> l = new ArrayList<String();
l.add("hoge");
l.add("fuga");
for (IndexableIterator.Entry<String> entry: new IndexableIterator<String>(l)) {
    int index = entry.getIndex();
    String v = entry.getValue();
    // do something...
}

みたいな感じですね。あとは、IndexableIteratorのTODOってところを実装すればいいだけです。



で、Java8のStream使って書こうかと思ったら、標準ライブラリからいつの間にかzipメソッドがなくなっているのね・・・。なので、Java8のstreamは池添さんが書いてくれるはず。

Java8のString::join

実際のコードを書きたかったのですが、すぐに思い出せないので、わずかながらの記憶で書きます。java8を使わない人も楽しめるはず。

SQL文を組み立てるときに、時々こんな感じのコードを見かけます。

コード1 ::
StringBuilder sb = new StringBuilder()
boolean isFirst = true;
for (int i=0; i<10; i++) {
    if (!isFirst) {
        sb.append(",");
    }
    sb.append("?");
}

もしくは、

コード2::
sb.append("column1");
sb.append(",");
sb.append("column2");
sb.append(",");
sb.append("column3");

ちょっと例が悪いですが、多分、こんな感じのコードにであったことはあると思います。アリエルのコードの場合、StringUtilsと言うクラスがいて、joinメソッドがあります。public static String StringUitls.join( Collection<String> elems, String delimiter)みたない感じです。

コード1のようなコードは、

String s = StringUtils.join(StringUtils.multiply("?", 10), ",")

って書けます。Javaは演算子のオーバーロードができないので、multipyってメソッドで*相当のことをしています。このへんはPythonの影響を受けているので、そっちを見るのがいいのかも。

コード2は

String s = StringUtils.join(new String[]{"column1", "column2", "column3"}, ",");

みたいな感じです。
アリエルの人たちは、「Stringにjoinがなくてめんどくさいな〜。でも、おれらはStringUtilsがあるからかんけーないね。」って思っていました。

さてさて、みんなが待ちに待ったJava8は華やかなlambdaやstream api、ついでにCalendar API(古いやつがスレッドセーフじゃないってどういうことじゃ!)も仲間に入れてあげるとして、そんな今どきの人に隠れてStringクラスの地味な拡張がjoinメソッドの追加です。アリエルはすぐにjava8に対応するので、これで十数行、全体のコード行が短くなるはず。えー、誤差の範囲です…。

で、Stringクラスにjoinメソッドが追加されて、コード1,2は次のようになります。

String s = String.join("," StringUtils.multiply("?", 10))
String s = String.join(", ", new String[]{"column1", "column2", "column3"});

スッキリ。
さて、Sting::joinはどうやって作っているのでしょうか?ちょっとだけコードを覗きます。3月11日のmercurialのリポジトリのコードです。

    public static String join(CharSequence delimiter,
            Iterable<? extends CharSequence> elements) {
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        StringJoiner joiner = new StringJoiner(delimiter);  // ①
        for (CharSequence cs: elements) {
            joiner.add(cs);  // ②
        }
        return joiner.toString(); // ③
    }

StringJoinerという新しいクラスが登場しています(①)。このクラスは、addした文字列(②)をdelemiterで連結してくれるクラスですね。最期に、文字列の出力です(③)。アリエルのStringUtils.joinはStringBuilderで文字列をその場で組み立てていました。ちょうど、コード1を汎用化した感じですね。


StringJoinerはコンストラクタが2つあって、
  StringJoiner(delimiter)
  StringJoiner(delemiter, prefix, suffix)

こんな感じで使えますね

StringJoiner sj = new StringJoiner(", ");
sj.add("column1");
sj.add("column2");
sj.add("column3");
sj.toString();   // column1, column2, column3になる

SQL文の組み立てだと最初と最期に( )が追加したいので、そういう時は、

StringJoiner sj = new StringJoiner(", ", "(", ")");
sj.add("column1");
sj.add("column2");
sj.add("column3");
sj.toString();   // (column1, column2, column3)になる

ほら、べんり。StingJoinerの実装でも、内部的なデータの保持はStringBuilderのオブジェクトを作っていて、その人にappendをしているだけですが、APIとしてはスッキリしていて、クラスの目的も明確ですね。





次のコードはStringJoinerのStringBuilderを取得しているコードです。valueはStringBuilderのクラスフィールドです。コード1だとisFirstというbooleanの値を見て、delemiterを追加するかどうか決めていましたが、value自体をフラグの代わりに使って、こんな風に書くとそういうフラグはいらないんですね。

  private StringBuilder prepareBuilder() {
        if (value != null) {
            value.append(delimiter);
        } else {
            value = new StringBuilder().append(prefix);
        }
        return value;
    }

それから、状況によっては、value.length()>0でdelemiterを追加するかどうかを決めるというのもできますね。


「私は、Stream APIとlambdaがあれば十分よ。String::joinなんていらない子よ」って。ごめんなさい。そういう人はそっちを使ってあげてください。

JITはすごいんだよ、とか

前回のリフレクションのベンチマークはJITの影響を受けています。Javaはコンパイル時だけじゃなくって実行時にももっと早くコードを実行できないか考えてくれるすごい子なのです。またはJITがないと使い物にならない速度でしか動かないかもしれません。普通に使用する分には可愛い子なのですが、ベンチマークするにはJITは厄介な子です。実際のソフトウエアとベンチマークでは最適化のされ方が異なるので、速度がかなり違ってきます。

で、前回の結果をJITのあるなしで計測すると次のようになります。

JITあり
=======
$ java timing.TimeCalls
Java version 1.7.0_51
Java HotSpot(TM) 64-Bit Server VM
24.51-b03
Oracle Corporation

Direct call using member field:
 231 7 6 6 6
 average time = 6 ms.
Direct call using passed value:
 8 6 6 6 6
 average time = 6 ms.
Call to object using member field:
 30 6 7 6 7
 average time = 7 ms.
Call to object using passed value:
 12 7 6 6 7
 average time = 7 ms.
Reflection call using member field:
 74 32 30 37 31
 average time = 33 ms.
Reflection call using passed value:
 179 151 145 127 120
 average time = 136 ms.

Direct call using member field:
 7 7 6 3 6
 average time = 6 ms.
Direct call using passed value:
 6 6 6 7 5
 average time = 6 ms.
Call to object using member field:
 6 6 5 7 6
 average time = 6 ms.
Call to object using passed value:
 6 6 6 6 6
 average time = 6 ms.
Reflection call using member field:
 39 31 34 38 28
 average time = 33 ms.
Reflection call using passed value:
 114 117 114 117 112
 average time = 115 ms.

JITなし
=======
$ java -Djava.compiler=none timing.TimeCalls
Java version 1.7.0_51
Java HotSpot(TM) 64-Bit Server VM
24.51-b03
Oracle Corporation

Direct call using member field:
 711 669 665 664 670
 average time = 667 ms.
Direct call using passed value:
 732 732 742 751 740
 average time = 741 ms.
Call to object using member field:
 730 696 675 676 676
 average time = 681 ms.
Call to object using passed value:
 673 686 673 681 677
 average time = 679 ms.
Reflection call using member field:
 4505 4487 4444 4448 4441
 average time = 4455 ms.
Reflection call using passed value:
 7293 7342 7386 7318 7359
 average time = 7351 ms.

Direct call using member field:
 680 666 672 679 667
 average time = 671 ms.
Direct call using passed value:
 742 736 736 744 742
 average time = 740 ms.
Call to object using member field:
 671 673 671 672 670
 average time = 672 ms.
Call to object using passed value:
 681 679 674 670 670
 average time = 673 ms.
Reflection call using member field:
 4453 4563 4521 4593 4565
 average time = 4561 ms.
Reflection call using passed value:
 7453 7307 7323 7348 7415
 average time = 7348 ms.


まあ、JITありに比べてない方は100倍遅いですね。ただし、今回は傾向は同じです。別の種類のベンチマークだと傾向が同じになるとは限りません。今回はループで何回も回していますが、最適化のされ方によってはループが回らなかったりします。

最終的にはDaoでDTOに値を詰めるって話にするつもりで、その場合メソッドの直接の呼び出しだとコストはほとんどかからない、リフレクションだとこれくらい、バイトコードを作るのはリフレクションよりは速そうだ、ってことぐらいがわかればイイかな、と。

本当はhibernateを使うのがいいのですが、これからのhibernateの導入は敷居が高いので、それじゃ似たようなコードのコピペをせずに、daoのコードをどれくらい少なくできるのか?ってことです。


それから、昔10倍遅かったと記憶していましたが、JITなしではちょうど10倍ぐらい遅いですね。記憶はあっていたのかもしれません。



http://www.ibm.com/developerworks/jp/java/library/j-jtp12214/

あれからJavaのリフレクションのスピードはどうなったのか?

僕が一番最近Javaのリフレクションのパフォーマンスを計測したのは、今のアリエルの開発を始めたぐらいで、ライブラリの選定をしている時でした。jdkのバージョンも覚えていません。それより前はいつやったのか覚えていません。
その時の結果の詳細は残っていませんが、リフレクションは通常のアクセスより10倍以上遅い、って印象だけが残っています。印象でものを語るのは良くないし、バージョンが上がるに連れて改善されているのかもしれないので、もう一度計測してみました。

以前は自分でコードを書いていたのですが、今回はサボって http://www.ibm.com/developerworks/jp/java/library/j-dyn0603/ にあるコードで試します。このページには1.4での計測結果ものっていて、いいかも。

ちなみに、今回はLinux上のSunのJDKでコンパイル・ビルド・実行しています。それから、結果に乗っている最初の一回目の数値は無視してください。

まず、リフレクションでオブジェクトを作るときの結果です。

Java version 1.7.0_51
Java HotSpot(TM) 64-Bit Server VM
24.51-b03
Oracle Corporation

Direct Object creation:
 49 1 2 1 2
 average time = 2 ms.
Reflection Object creation:
 44 3 3 2 3
 average time = 3 ms.
Direct byte[8] creation:
 10 7 8 11 10
 average time = 9 ms.
Reflection byte[8] creation:
 12 8 8 8 8
 average time = 8 ms.
Direct byte[64] creation:
 101 79 37 8 7
 average time = 33 ms.
Reflection byte[64] creation:
 7 7 7 8 8
 average time = 8 ms.

Direct Object creation:
 2 2 1 3 1
 average time = 2 ms.
Reflection Object creation:
 2 4 5 4 4
 average time = 4 ms.
Direct byte[8] creation:
 9 6 7 8 8
 average time = 7 ms.
Reflection byte[8] creation:
 8 8 10 9 8
 average time = 9 ms.
Direct byte[64] creation:
 9 8 11 9 7
 average time = 9 ms.
Reflection byte[64] creation:
 9 11 11 10 8
 average time = 10 ms.

オブジェクトの作成は若干リフレクションの方が遅いですが、使用用途にもよりますが、この程度であればリフレクションを使ってもそれほどオーバーヘッドもなく、問題ないでしょう。


次にオブジェクトの中のフィールドへのアクセスです。昔、偉い人が「privateなんて飾りです。リフレクションをシラン人はわからんのです。」って言っていましたが、それがこういうことです。
で、結果ですが、


Java version 1.7.0_51
Java HotSpot(TM) 64-Bit Server VM
24.51-b03
Oracle Corporation

Direct access using member field:
 8 6 6 7 6
 average time = 6 ms.
Reference access to member field:
 28 7 7 5 7
 average time = 7 ms.
Reflection access to member field:
 3544 3486 3437 3433 3482
 average time = 3460 ms.

Direct access using member field:
 7 5 7 6 6
 average time = 6 ms.
Reference access to member field:
 6 6 6 6 6
 average time = 6 ms.
Reflection access to member field:
 3538 3555 3515 3545 3482
 average time = 3524 ms.

で、reference accessはまあ、どうでもいいです。reflection accessだと、10倍どころじゃないですね。600倍ぐらい遅いです。数回だけならまだしも、アクセス数が増えると使い物にならないですね。JRubyとかJPythonは、基本的にメンバー変数に直接アクセスはしないんだろうか?

最後にメソッドの呼び出しです。

Java version 1.7.0_51
Java HotSpot(TM) 64-Bit Server VM
24.51-b03
Oracle Corporation

Direct call using member field:
 8 7 6 6 3
 average time = 6 ms.
Direct call using passed value:
 11 6 3 6 7
 average time = 6 ms.
Call to object using member field:
 10 6 7 7 6
 average time = 7 ms.
Call to object using passed value:
 8 6 5 7 6
 average time = 6 ms.
Reflection call using member field:
 71 32 30 29 33
 average time = 31 ms.
Reflection call using passed value:
 158 139 138 122 117
 average time = 129 ms.

引数なしでの呼び出しは、通常の5倍遅いです。引数ありでは20倍の遅さです。メンバー変数へ直接アクセスすするよりは、メソッドを通してアクセスするほうが効率は良さそうですね。

IBMのサイトの結果と比べると…、IBMのサイトのグラフが対数になっていて、よくわかりません。多分、あんまり変わっていないです。

ということで、

- リフレクションでのオブジェクトの作成はオーバーヘッドがほとんどない
- メンバーフィールドにアクセスするのは遅すぎるのでやらないほうがいい。
- メソッド呼び出しは5から20倍遅いので、使う場合は注意する

2014年3月13日

javaのiteratorとかiterable


※ とあるところに書いたものの転載です。
※ Java8の話はまた、あとで


こんなコードよく書くよね。


BufferedReader reader = new BufferedReader(new FileReader("myfile.txt"));
String line = null;
while ((line = reader.readLine()) != null) {
     System.out.println(line);
}

まあ、でも、ループの条件式とのとことか、微妙でわかりにくいし、変数のスコープも大きいよね。と言うか、どっかのスクリプト言語みたいに


BufferedReader reader = new BufferedReader(new FileReader("myfile.txt"));
for (String line: reader) {
     System.out.println(line);
}

みたいに書きたくない?
ということで、そこら辺のもの。拡張forループとか言っても、結局iterator使ってグルグルイテレートしているだけ。なんで、イテレートできるようにしてあげたら上みたいな感じで書けるはず。ちなみに、拡張forループ使わずに

for (Iterator iter = reader.iterator(); iter.hasNext();) {
    String line = iter.next();

みたいな書き方は全く嬉しくないので、forループが拡張されたからやりたくなることですね。
さて、実行時にbufferedReaderにメソッドを追加するとかは危険なので今回はBufferedReaderを拡張したIterableReaderを作っちゃいます。

import java.util.*;
import java.io.*;

public class A {
    public static class IterableReader extends BufferedReader implements Iterable {
        public IterableReader(Reader in) {
            super(in);
        }
        public IterableReader(Reader in, int sz) {
            super(in, sz);
        }
        public Iterator iterator() {
            try {
                final String l = readLine();
                return new Iterator() {
                    String last = l;
                    public boolean hasNext() {
                        return last != null;
                    }
   
                    public String next() {
                        String result = last;
                        if (last != null) {
                            try {
                                last = readLine();
                            } catch (IOException e) {
                                throw new RuntimeException(e);
                            }
                        }
                        return result;
                    }

                    public void remove() {
                    }
                };
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

        public static void main(String[] argv) {
        try (IterableReader reader = new IterableReader(new FileReader(argv[0]))) {
            for (String line: reader) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
       }

}

Iterableを実装したクラスを作ってあげて、その中でIteratorを返せばいいだけ。ちなみに、無名クラスにもコンストラクタ、書きたい…。
IOExceptionを投げられないので、RuntimeExceptionで代用しているのは許してください。

try-with-resource statementはjava7からだったのか…

※ とあるところで書いたことの転載です

普段、Java7で生活しているとJava6だとめんどうだなー、って感じることがありますよね。みんな早くJava7とかJava8に移行したほうがいいよね。

って言うことで、IO関係の処理ってcloseメソッドってIOExceptionがつきまっとっていて、うざいよね。みんなこんな感じで書いていると思うんだ。

InputStream io = null;

try {
    io = new FileInputStream("somefile")
    いろんな処理
} catch (IOException e) {
    例外処理的な何か
} finally {
    if (io != null) {
        try {
            io.close();
        } catch (IOException e) {
            // なんもしない
       }
    }
}

沢山の行数が必要ですね。Javaはなんと生産性の高いことか!じゃあ、Java7だとどうなるのか、って言うと、

try (InputStream io = new FileInputStream("somefile")) {
     いろんな処理
} catch (IOException e) {
    例外処理的な何か
}

はい、おしまい。余分なことが抜けてスッキリして、必要最小限のことに
CloseableかAutoCloseableのインターフェースを継承している人なら、tryから抜けてfinallyに入る直前に後始末をしてくれます。ちょーべんりー。プログラマは怠惰なものさ、ってきっとATEの誰かが言っています。
自動でクローズされなくても、スコープがtry節の中に限定されるだけでもスッキリします。(変数はなるべく局所化したほうがいい)

でも、プロダクトでJava7に上げてもらえないんですぅ。そんなあなたにlombok。この子さえいれば、さらにハッピーに。


@Cleanup InputStream io = new FileInputStream("somefile")
いろんな処理


@Cleanupは http://projectlombok.org/features/Cleanup.html
もう、魔法ですね。ただしlombokはバイトコードをいじるので、導入には許可をとってからにしましょう。一度、この子に触れると、普通のJavaは書けない体になってしまうので、気をつけましょう。

ちなみに、上の奴はさらに短く…

@Cleanup val io = new FileInputStream("somefile")
いろんな処理

どきどきJavaの国際化

※ とあるところでかいたものの転載


それでは、それでは。

変数名とかに英語表記ではなく、ローマ字で記述しているコードって沢山あるじゃないですか?アリエルは開発フレームワークなので、Javaのコードにはローマ字表記はコーディング規約として許していませんが、その上で作るアプリケーション(JavaScriptで記述)はちょっとカオスなところがあって、変数名にローマ字表記されているところもあります。

あっ、今回もJavaのお題です。僕はJavaScriptは嫌いなので…。

例えばこんな感じ

  public class MyClass {
      private int hensu = 1;

      public int add(int v) {
          hensu += v;
          return hensu;
     }
          
      public static void main(String[] argv) {
          MyClass obj = new MyClass();
          System.out.println(obj.add(10));
      }
  }

英語でもそうですけど、ローマ字でも読みにくいですよね。日本人なら日本語(漢字とかひらがな、カタカナ)ですよね。
ということで、変数名も日本語にしちゃいましょう!


  public class MyClass {
      private int 変数 = 1;

      public int add(int v) {
          変数 += v;
          return 変数;
     }
          
      public static void main(String[] argv) {
          MyClass obj = new MyClass();
          System.out.println(obj.add(10));
      }  }

ほら、読みやすくなった。じゃあ、メソッドも日本語化したほうがわかりやすくなるんじゃない?


  public class MyClass {
      private int 変数 = 1;

      public int 加算(int 入力値) {
          変数 += 入力値;
          return 変数;
      }

      public static void main(String[] argv) {
          MyClass インスタンス = new MyClass();
          System.out.println(インスタンス.加算(10));
      }
  }

ほら、スッキリした。クラス名も日本語に…。えーと、僕は日本語のファイル名があまり好きではないので、それはしません。インナークラスだったら許せます。なので、


  public class MyClass {
      static class 算術クラス {
          private int 変数 = 1;
         
          public int 加算(int 入力値) {
              変数 += 入力値;
              return 変数;
          }
      }

      public static void main(String[] コマンドライン引数) {
          算術クラス インスタンス = new 算術クラス();
          System.out.println(インスタンス.加算(10));
      }
  }


ほら、すごーく分かりやすい。Javaって素敵。でも、悲しいことが2つあります。1つ目はIMEを切り替えながら使わないといけないこと。これは、慣れの問題なのでがんばりましょう。もうひとつは、エディタによっては、全角空白が入り込むと、見つけるのがちょっと大変になることかな。

そう言えば、アリエルもJavaのテストコードに日本語のメソッド名を使っているところがあったような気がする。
ちなみに、pythonで同じようなことをした時のもの。
  http://blog.liris.org/2012/02/python3.html


※ 今回はネタでした。
※ 次回はlombokかもしれない。でも、スレッドのお話かもしれない。グローバル変数についてのお話かもしれない。

javaのEnumSet

とあるところで書いたものの転載 

EnumSetは、ビット集合を扱っていないとよくわかってもらえないんじゃないかと思ってるんですが、EnumSetについてのお話です。
Cの世代のビット演算大好きなおっさんの話は書かないので、そっちは自分で調べてください。それから、メモリの話もしないです。

それから、これを読むときはカービーダンスの樫木先生のしゃべり方を思い出しながら読んでね。

-----------------

さて、コードの中を見ていると、こんな感じでbooleanで設定のon/offを制御しているところが沢山あるんだよ。

class MySomeClass {
    private boolean opt_1 = false;
    private boolean opt_2 = false;
    private boolean opt_3 = false;
    private boolean opt_4 = false;
     :
}

多分、コードを書いている人はこんなの沢山見ているはずだよ。前回のenumの場合、オプションでとりうる値が複数あって、その中の一個を指定できるってことだったんだよね。でも、今回みたいに、booleanで複数のオプションがあって、その組み合わせがある場合、enumだけだと制御できないよね。

で、そんな組み合わせを簡単に扱えるようにするのがEnumSetなんだ。って言っても、わかんないよね。
コードで見ていったほうがいいかな。

オプション関係は一つのまとまりなので、まとまりはまとまりとしてわかりやすくしたいよね。で、enumでオプション関係をきり出しちゃいます。

class MySomeClass {
   static enum MyOpt { opt_1, opt_2, opt_3, opt4 };
}

それで、実際の値を保持する部分はEnumSetに指定するよ。

class MySomeClass {
   public static enum MyOpt { opt_1, opt_2, opt_3, opt_4 };
   private EnumSet opt = EnumSet.noneOf(MyOpt.class);
}

こんな感じで、4つあったオプションのフィールドが一個にまとまっちゃいました。
実際に使うときは、普通のSetと同じように扱えるよ。

  opt.add(MyOpt.opt_1)

って感じでオプションをセットできるよ。

  opt.contains(MyOpt.opt_2)

のようにして、値がセットされているかどうか判定できるよ。使うときにbooleanそのものよりもちょっと面倒だけどね。

値を削除するのはremoveだよ。


もうちょっと別の使い方は、メソッドの引数がbooleanの羅列で動作を変える場合だよね。
こんなメソッド、気がついたらよくできちゃっているのよね。

public void func(boolean opt1, boolean opt2, boolean opt3, boolean opt4) {
   :
}

で、さらに今回opt5が必要になった・・・。悪夢だよ。そんなら

public void func(EnumSet opt) {
   :
}

ほら、スッキリした。使う方は、メソッドのマニュアルを見ながら、オプションの意味を確認していたのが、enumの値を見ればオプションの意味をしることができるよ。
最後に呼び出し元を見てみよう。

func(true, false, false, true);

  ↓

func(EnumSet,of(MyOpt.opt1, MyOpt.opt4));

どっちが分かりやすい?




うーん、やっぱりビットのお話から入ったほうが良かった?

javaのenum

とあるところで書いたものの転載


昔のコード

  int sex = 0; // 1: male, 2: female, 0: other

数字の意味が思い出せない年寄りのために、昔のコードをちょっとだけリファクタリング

  public static final int SEX_MALE = 1;
  public static final int SEX_FEMALE = 2;
  public static final int SEX_OTHER = 0;

  int sex = SEX_OTHER;

でも、こんなコードが何処かで…

  this.sex = 3;

maleとfemaleを足しあわせたものはOTHERじゃなくって、3という発明をしちゃった開発者が…。そんな発明は素敵だけど、もう、させないぞ。

  public enum Sex {
      MALE(1),
      FEMALE(2),
      OTHER(0);

     private int v;
    
     private Sex(int v) {
         this.v = v;
     }
   
     public int getIntValue() {
        return v;
     }
  }

  Sex sex = Sex.OTHER;

※ public enum sex {OTHER, MALE, FEMALE}でもいいけど、特別な値もいれられるために、あえて上のように書いています。

これで、MALEとFEMALEを足しあわせたものは、勝手に作れなくなったよ。


でも、formがポストしてくるのはfemaleとかmaleとかの文字列です。どうやって、区別するんですか?

  if (value.equals("male")) {
     sex = Sex.MALE;
  } else if (value.equals("female")) {
    sex = Sex.FEMALE;
  } else {
    sex = Sex.OTHER;
  }

嘘です。こんなコード、書いていたら、アリエルのこわーい中山さんという人に袋たたきに会います。

  sex = Sex.valueOf(value.toUpperCase());


でも、フォームの場所によっては数字で来るんです。
じゃあ、Sexがもっといろいろできるようにしたちゃえ。

   public enum Sex {
     : 中略
     public Sex valueOf(int v) {
        for (Sex s: Sex.values()) {
            if (s.getIntValue() == v) {
                return s;
            }
         }
         return OTHER;
     }
   }

でも、変な値が来たら無条件にOTHERにするのはどうも・・・。ということで

     public Sex valueOf(int v) {
        for (Sex s: Sex.values()) {
            if (s.getIntValue() == v) {
                return s;
            }
         }
         throws IllegalArgumentException("sex : " + v);
     }

2014年1月22日

bcryptのラウンド回数と実行時間

「sha? md5? じじい!」って会社の@kirisに罵倒された気がして、「ナウでヤングな若者はbcryptだよ」と蔑んだ目で見られたので、bcryptでround回数を変更すると実行時間はどうなるんだろう?って言うことで、計測してみました。bcryptが何なのか、ってのは、自分で調べてね。
py-bcrypt使って計測していますが、計算処理はCのコードで書かれているっぽいです。

コードは、

import timeit
for i in range(1,20):
    print timeit.timeit("bcrypt.hashpw('password', bcrypt.gensalt(" + str(i) + "))", setup="import bcrypt", number=1)

です。計測結果ですが、

ラウンド数時間(sec)
1 0.002
2 0.002
3 0.002
4 0.002
5 0.004
6 0.004
7 0.007
8 0.015
9 0.031
10 0.063
11 0.125
12 0.256
13 0.516
14 1.0121
15 1.9985
16 4.0332
17 8.0246
18 16.1026
19 32.1371
20 64.3373

グラフにするとこんな感じ。
いい感じに計算時間が伸びていきます。でも、デフォルトでは12回でそれが256m secはちょっと遅いですね。計測したスペックのマシンだと10回か11回が限界ですね。100m secには収めたい。

2014年1月17日

OpenAMとか

最近、OpenAMを使ったので、その時のメモ。
セットアップの仕方とか、エージェントの設定の仕方は井上大先生のコラムを読めばいいです。OpenAMはOpenSSOからフォークしたものです。なので、名前が多少違いますが、セットアップの仕方とか、ほとんど同じです。それから、OpenAM ver. 10はtomcat 8.0 RC1とかじゃ起動しなかったので、tomcat 7などの安定したバージョンを使いましょう。

さて、OpenAMへの経緯ですが、要求として次のものがありました。

  • 複数のシステムでSSO
  • 認証基盤の統一
  • 認証強度をプラグイン的に変更可能
ごく一般的な要求ですね。

複数システムでのSSOは、OpenAMの前進のOpenSSOの名前が示す通り、シングルサインオンするものです。毎回、ログイン画面がでるのは嫌で、一度どこかで認証を済ませておけば、他のシステムへログインせずに入って行きたい、ってことですね。
OpenAMじゃなくっても、Windowsの世界であればWindows統合認証でSSOが可能です。AD FSをセットアップすれば、SAML認証が使えるようになるので、Google AppsなどでもSSOが可能になります。でも、会社によってはADを管理しているところがガチガチだと、ADにお触りするのは結構ハードルが高かったりします。反対に、ADが名前だけになっていて、まずADはあるけど意味がない状態のところもあったりで、なんとも悩ましいところです。

認証基盤の統一と言うか、 自前で認証をするのはそろそろやめるべきじゃなかろうか、と思い始めているからです。これは次の認証強度をプラグイン的に変更可能、っていうのもあるんですが、今後、認証まわりは強化される方向に行くんじゃないかな、って。最初はインターネットにさらされているものだけが、認証を強化する必要があると考えていましたが、イントラネット内でも同じ程度にセキュリティを意識しなければいけなくなりつつあると。
認証を次第に強化していく時に、プラグイン的に(設定で)強度を変更できるようにしておきたいです。例えば、フォーム認証から、2要素認証に変更したいとか、ログインを試行したロケーションによって制御したいとか。アリエルの製品はSpring FrameworkをベースにしていてSpring Securityを使えば、ある程度これらのことは実現可能ですが、これらの認証をもっと粗結合にして外部に切り出したいですね。これらを切り出せれば、他のシステムも少しの対応で認証が強化されます。

ということでOpenAMや、商用のSSOの製品を今後ちゃんと検討する必要があると感じています。

でも、SSOなので、最初の認証さえ突破されればおぞましい世界が待ち受けていますね。

おっとポリシーエージェントの動きとか説明しようと思っていたけど、そっちはまた、気が向いたら。