Я реализовал небольшую функциональную библиотеку для этой утилиты. Один из методов имеет эту подпись:
<T> List<T> mapToProperty(List<?> objectList, String property, Class<T> returnType)
Что берет строку и использует отражение для создания вызова свойства, а затем возвращает список, поддерживаемый objectList, где get и iterator реализованы с использованием этого вызова свойства .
Функции mapToProperty реализованы в терминах общей функции карты, которая принимает функцию как средство отображения, хотя, как описано в другой статье. Очень полезно.
Предлагаю вам ознакомиться с базовым программированием функций и, в частности, взглянуть на функторы (объекты, реализующие функцию карты)
Редактировать: отражению действительно не нужно быть дорогим. В этой области JVM значительно улучшилась. Просто убедитесь, что один раз скомпилировали вызов и повторно его использовали.
Edit2: Пример кода
public class MapExample {
public static interface Function<A,R>
{
public R apply(A b);
}
public static <A,R> Function<A,R> compilePropertyMapper(Class<A> objectType, String property, Class<R> propertyType)
{
try {
final Method m = objectType.getMethod("get" + property.substring(0,1).toUpperCase() + property.substring(1));
if(!propertyType.isAssignableFrom(m.getReturnType()))
throw new IllegalArgumentException(
"Property "+property+" on class "+objectType.getSimpleName()+" is not a "+propertyType.getSimpleName()
);
return new Function<A,R>()
{
@SuppressWarnings("unchecked")
public R apply(A b)
{
try {
return (R)m.invoke(b);
} catch (Exception e) {
throw new RuntimeException(e);
}
};
};
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static <T1,T2> List<T2> map(final List<T1> list, final Function<T1,T2> mapper)
{
return new AbstractList<T2>()
{
@Override
public T2 get(int index) {
return mapper.apply(list.get(index));
}
@Override
public int size() {
return list.size();
}
};
}
@SuppressWarnings("unchecked")
public static <T1,T2> List<T2> mapToProperty(List<T1> list, String property, Class<T2> propertyType)
{
if(list == null)
return null;
else if(list.isEmpty())
return Collections.emptyList();
return map(list,compilePropertyMapper((Class<T1>)list.get(0).getClass(), property, propertyType));
}
}