CUBは子供の白熊

Java SE 8 実践プログラミングの練習問題を解く

第3章 ラムダ式を使ったプログラミング : 問題 9 : リフレクションによる Comparator の生成

問題

指定された順序で指定されたフィールドを比較するComparatorを生成するメソッド

Comparator<?> lexicographicComparator(String... fieldNames)

を書け。

例えば

lexicographicComparator("lastname", "firstname")

  1. 2つのObjectを引数に受け取り
  2. リフレクションを使用して lastname フィールドの値を取得
  3. 2つのObjectの lastname フィールドが異なるときは、その比較結果を返す
  4. リフレクションを使用して firstname フィールドの値を取得
  5. 2つのObjectの firstname フィールドが異なるときは、その比較結果を返す
  6. 0 を返す

というふうに動作するComparatorを返す。

解答

オブジェクトのメンバーといえば、フィールドではなくプロパティを参照するのが普通だが、言われたとおりフィールドに限定しよう。

まず、オブジェクトからフィールド値を取得するメソッドを実装する。

■ オブジェクトからフィールドを取得

private static Object getFieldValue(Object target, String fieldName) {
    // private なフィールドの値も取得
    for (Class<?> clazz = target.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
        Field field;
        try {
            field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(target);
        } catch (IllegalAccessException ex) {
            // 事前にアクセス可にしているので、ありえない
            throw new RuntimeException(ex);
        } catch (NoSuchFieldException ex) {
            // 親クラスを調べる
        }
    }
    // このオブジェクトは指定されたフィールドを持たない
    throw new RuntimeException();
}

このメソッドを使ってComparatorを生成する。

Comparatorの生成

public static Comparator<?> lexicographicComparator(String... fieldNames) {
    return (t, u) -> {
        for (String fieldName : fieldNames) {
            Object tf = getFieldValue(t, fieldName);
            Object uf = getFieldValue(u, fieldName);
            if (tf.equals(uf)) {
                continue;
            }
            return ((Comparable)tf).compareTo(uf);
        }
        return 0;
    };
}