第3章 ラムダ式を使ったプログラミング : 問題 9 : リフレクションによる Comparator の生成
問題
指定された順序で指定されたフィールドを比較するComparator
を生成するメソッド
Comparator<?> lexicographicComparator(String... fieldNames)
を書け。
例えば
lexicographicComparator("lastname", "firstname")
は
- 2つの
Object
を引数に受け取り - リフレクションを使用して lastname フィールドの値を取得
- 2つの
Object
の lastname フィールドが異なるときは、その比較結果を返す - リフレクションを使用して firstname フィールドの値を取得
- 2つの
Object
の firstname フィールドが異なるときは、その比較結果を返す - 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; }; }