Java:如何将 List<?> 转换为 Map<String,?>
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3199657/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java: how to convert a List<?> to a Map<String,?>
提问by ebt
I would like to find a way to take the object specific routine below and abstract it into a method that you can pass a class, list, and fieldname to get back a Map. If I could get a general pointer on the pattern used or , etc that could get me started in the right direction.
我想找到一种方法来获取下面的对象特定例程并将其抽象为一个方法,您可以通过该方法传递类、列表和字段名来获取 Map。如果我能得到关于所用模式的一般指针,或者等等,这可以让我朝着正确的方向开始。
Map<String,Role> mapped_roles = new HashMap<String,Role>();
List<Role> p_roles = (List<Role>) c.list();
for (Role el : p_roles) {
mapped_roles.put(el.getName(), el);
}
to this? (Pseudo code)
到这个?(伪代码)
Map<String,?> MapMe(Class clz, Collection list, String methodName)
Map<String,?> map = new HashMap<String,?>();
for (clz el : list) {
map.put(el.methodName(), el);
}
is it possible?
是否可以?
采纳答案by quantumSoup
Here's what I would do. I am not entirely sure if I am handling generics right, but oh well:
这就是我要做的。我不完全确定我是否正确处理泛型,但是哦:
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;
}
Just pass a Collection to it, and have your classes implement toString() to return the name. Polymorphism will take care of it.
只需将 Collection 传递给它,并让您的类实现 toString() 以返回名称。多态会处理它。
回答by Michael
Using reflection and generics:
使用反射和泛型:
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;
}
In your documentation, make sure you mention that the return type of the method must be a String. Otherwise, it will throw a ClassCastException when it tries to cast the return value.
在您的文档中,确保您提到该方法的返回类型必须是字符串。否则,它会在尝试转换返回值时抛出 ClassCastException。
回答by Tom Hawtin - tackline
Avoid reflection like the plague.
避免像瘟疫一样的反思。
Unfortunately, Java's syntax for this is verbose. (A recent JDK7 proposal would make it much more consise.)
不幸的是,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;
}
Currently call as:
目前调用为:
Map<String,Thing> map = stringIndexOf(
things,
new ToString<Thing>() { public String toString(Thing thing) {
return thing.getSomething();
}
);
In JDK7, it may be something like:
在JDK7中,它可能是这样的:
Map<String,Thing> map = stringIndexOf(
things,
{ thing -> thing.getSomething(); }
);
(Might need a yield
in there.)
(可能需要yield
在那里。)
回答by Jorn
Using Guava (formerly Google Collections):
使用Guava(以前的 Google Collections):
Map<String,Role> mappedRoles = Maps.uniqueIndex(yourList, Functions.toStringFunction());
Or, if you want to supply your own method that makes a String
out of the object:
或者,如果您想提供自己的方法来String
生成对象:
Map<String,Role> mappedRoles = Maps.uniqueIndex(yourList, new Function<Role,String>() {
public String apply(Role from) {
return from.getName(); // or something else
}});
回答by ColinD
If you're sure that each object in the List
will have a unique index, use Guavawith Jorn's suggestion of Maps.uniqueIndex
.
如果您确定 中的每个对象List
都有唯一的索引,请使用Guava和 Jorn 的Maps.uniqueIndex
.
If, on the other hand, more than one object may have the same value for the index field (which, while not true for your specific example perhaps, is true in many use cases for this sort of thing), the more general way do this indexing is to use Multimaps.index(Iterable<V> values, Function<? super V,K> keyFunction)to create an ImmutableListMultimap<K,V>
that maps each key to one or more matching values.
另一方面,如果多个对象的索引字段可能具有相同的值(虽然对于您的特定示例可能并非如此,但在此类事情的许多用例中都是如此),更通用的方法是这种索引是使用Multimaps.index(Iterable<V> values, Function<? super V,K> keyFunction)创建一个ImmutableListMultimap<K,V>
将每个键映射到一个或多个匹配值的索引。
Here's an example that uses a custom Function
that creates an index on a specific property of an object:
这是一个使用自定义的示例,该自定义Function
在对象的特定属性上创建索引:
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")) { ... }
回答by Jeffrey Bosboom
Java 8 streams and method references make this so easy you don't need a helper method for it.
Java 8 流和方法引用使这变得如此简单,您不需要辅助方法。
Map<String, Foo> map = listOfFoos.stream()
.collect(Collectors.toMap(Foo::getName, Function.identity()));
If there may be duplicate keys, you can aggregate the values with the toMap overload that takes a value merge function, or you can use groupingByto collect into a list:
如果可能有重复的键,您可以使用采用值合并函数的toMap 重载聚合这些值,或者您可以使用groupingBy收集到一个列表中:
//taken right from the Collectors javadoc
Map<Department, List<Employee>> byDept = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
As shown above, none of this is specific to String -- you can create an index on any type.
如上所示,这些都不是 String 特有的——您可以在任何类型上创建索引。
If you have a lot of objects to process and/or your indexing function is expensive, you can go parallel by using Collection.parallelStream()
or stream().parallel()
(they do the same thing). In that case you might use toConcurrentMapor groupingByConcurrent, as they allow the stream implementation to just blast elements into a ConcurrentMap instead of making separate maps for each thread and then merging them.
如果你有很多对象要处理和/或你的索引功能很昂贵,你可以通过使用Collection.parallelStream()
或stream().parallel()
(它们做同样的事情)并行。在这种情况下,您可以使用toConcurrentMap或groupingByConcurrent,因为它们允许流实现只将元素爆炸到 ConcurrentMap 而不是为每个线程制作单独的映射然后合并它们。
If you don't want to commit to Foo::getName
(or any specific method) at the call site, you can use a Function passed in by a caller, stored in a field, etc.. Whoever actually creates the Function can still take advantage of method reference or lambda syntax.
如果您不想Foo::getName
在调用站点提交(或任何特定方法),您可以使用调用者传入的函数,存储在字段中等。 实际创建函数的人仍然可以利用方法参考或 lambda 语法。