Этот вопрос уже имеет ответ здесь:
Я хотел бы найти способ взять объектную определенную стандартную программу ниже и абстрагировать ее в метод, что можно передать класс, список и имя поля для возвращения Карты. Если я мог бы получить общий указатель на используемом шаблоне или, и т.д. который мог бы запустить меня в правильном направлении.
Map mapped_roles = new HashMap();
List p_roles = (List) c.list();
for (Role el : p_roles) {
mapped_roles.put(el.getName(), el);
}
к этому? (Псевдо код)
Map MapMe(Class clz, Collection list, String methodName)
Map map = new HashMap();
for (clz el : list) {
map.put(el.methodName(), el);
}
действительно ли это возможно?
Вот что бы я сделал. Я не совсем уверен, правильно ли я обрабатываю дженерики, но да ладно:
public <T> Map<String, T> mapMe(Collection<T> list) {
Map<String, T> map = new HashMap<String, T>();
for (T el : list) {
map.put(el.toString(), el);
}
return map;
}
Просто передайте ему коллекцию, и пусть ваши классы реализуют toString () для возврата имени. Об этом позаботится полиморфизм.
Использование Guava (ранее Google Collections):
Map<String,Role> mappedRoles = Maps.uniqueIndex(yourList, Functions.toStringFunction());
Или, если вы хотите поставить свой собственный метод, который делает String
из объекта:
Map<String,Role> mappedRoles = Maps.uniqueIndex(yourList, new Function<Role,String>() {
public String apply(Role from) {
return from.getName(); // or something else
}});
Использование отражения и дженериков:
public static <T> Map<String, T> MapMe(Class<T> clz, Collection<T> list, String methodName)
throws Exception{
Map<String, T> map = new HashMap<String, T>();
Method method = clz.getMethod(methodName);
for (T el : list){
map.put((String)method.invoke(el), el);
}
return map;
}
Убедитесь, что в вашей документации вы упомянули, что возвращаемый тип метода должен быть String. В противном случае он вызовет исключение ClassCastException, когда попытается преобразовать возвращаемое значение.
Если вы уверены, что каждый объект в List
будет иметь уникальный индекс, используйте Guava с предложенным Йорном Maps.uniqueIndex
.
Если, с другой стороны, более одного объекта могут иметь одинаковое значение для поля index (что, хотя и не верно для вашего конкретного примера, возможно, верно во многих случаях использования такого рода вещей), более общий способ сделать такую индексацию - использовать Multimaps. index(IterableImmutableListMultimap
, который сопоставляет каждый ключ с одним или несколькими подходящими значениями.
Вот пример, использующий пользовательскую функцию
, которая создает индекс на определенном свойстве объекта:
List<Foo> foos = ...
ImmutableListMultimap<String, Foo> index = Multimaps.index(foos,
new Function<Foo, String>() {
public String apply(Foo input) {
return input.getBar();
}
});
// iterate over all Foos that have "baz" as their Bar property
for (Foo foo : index.get("baz")) { ... }
Избегайте отражений как чумы.
К сожалению, синтаксис Java для этого многословен. (Недавнее предложение JDK7 сделало бы его гораздо более лаконичным.)
interface ToString<T> {
String toString(T obj);
}
public static <T> Map<String,T> stringIndexOf(
Iterable<T> things,
ToString<T> toString
) {
Map<String,T> map = new HashMap<String,T>();
for (T thing : things) {
map.put(toString.toString(thing), thing);
}
return map;
}
В настоящее время он выглядит так:
Map<String,Thing> map = stringIndexOf(
things,
new ToString<Thing>() { public String toString(Thing thing) {
return thing.getSomething();
}
);
В JDK7 это может быть что-то вроде:
Map<String,Thing> map = stringIndexOf(
things,
{ thing -> thing.getSomething(); }
);
(Возможно, там понадобится yield
.)