関数型言語スタイルのリスト内包表記に似たものを提供するGuavaのようなものを使用することで、このようなもののコードサイズを減らすことができます。
インターフェイスを定義することにより、これの一部を自分でロールすることもできます
public interface Predicate<T> {
boolean apply(T obj);
}
それを使用してファインダーメソッドを作成します。
B findElementByPredicate(Predicate<B> predicate) {
for (B b : list) {
if (predicate.apply(b))
return b;
}
return null;
}
(コメントに記載されているように)リフレクションを使用してフィールドの値を取得することもできます。arne.bの回答で定義されたインターフェースを実装すると、定義できます
public class ReflectivePropertyExtractor<T, P> implements PropertyExtractor<T, P> {
String fieldName;
public ReflectivePropertyExtractor(String fieldName) {
this.fieldName = fieldName;
}
@Override
public P getProperty(T obj) {
try {
Method m = B.class.getMethod(makeAccessorName());
return (P) m.invoke(obj);
} catch (InvocationTargetException e) {
return null;
} catch (NoSuchMethodException e) {
return null;
} catch (IllegalAccessException e) {
return null;
}
}
private String makeAccessorName() {
return "get" + capitalize(fieldName);
}
private String capitalize(String s) {
if ((s == null) || (s.length() == 0))
return s;
return s.substring(0, 1).toUpperCase() + s.substring(1);
}
}
指定されたフィールド名に対して機能するプロパティエクストラクタを作成し、彼が回答で説明したようにそれを使用するか、それに基づいて述語を作成します。
public class PropertyMatchPredicate<T, P> implements Predicate<T> {
private final P matchValue;
private final PropertyExtractor<T, P> extractor;
public PropertyMatchPredicate(P matchValue, PropertyExtractor<T, P> extractor) {
this.matchValue = matchValue;
this.extractor = extractor;
}
@Override
public boolean apply(T obj) {
return matchValue.equals(extractor.getProperty(obj));
}
}
そして、その述語をfindByPredicate
上記で使用します。
B findElementByProperty(String matchField, final String matchValue) {
final ReflectivePropertyExtractor<B, String> extractor = new ReflectivePropertyExtractor<B, String>(matchField);
return findElementByPredicate(new PropertyMatchPredicate<B, String>(matchValue, extractor));
}
2 つのプロパティのみを扱っている場合、これらの戦術はすべて、コード サイズを縮小するのではなく、増加させる可能性があります。利点はより大きな規模でのみ発生し、機能スタイルやリフレクションに慣れていない人にとってコードが読みにくくなるという代償を払う可能性があります。