背景:最近使用比较多的mongodb,由于其缺乏表连接的查询,导致我们经常需要将表数据查询到内存中,然后进行匹配连接,组成需要的数据格式,匹配的方式通常是:
list1中有list2需要的字段,于是将list1转换为map,遍历list2,从map中找到对应的数据字段。当面对大量的这样的业务操作的时候,一个个写将list转换为map的小代码段,是非常浪费时间,容易出错且无益的,所以抽时间将这个方法写下来,以便以后使用。
本人在写这个方法的时候,只改进过一次,执行效率上和原始的转换代码效率差距不大了,是可以使用的方法了
现在增加了java8的流的方式的对比,可以供参考
public static class DemoClass{
private Integer id;
private String name;
public DemoClass(){}
public DemoClass(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static Map traditionalWay(List list) {
Map map = new HashMap();
if (list != null) {
for (int i = 0; i < list.size(); i++) {
DemoClass value = list.get(i);
map.put(value.getId(), value);
}
}
return map;
}
下面来实现通用接口
方法名为
public static Map list2Map(List list, String fieldName4Key);
public static Map list2Map1(List list, String fieldName4Key) {
Map map = new HashMap();
if (list != null) {
try {
for (int i = 0; i < list.size(); i++) {
V value = list.get(i);
@SuppressWarnings("unchecked")
K k = (K) BeanUtils.getProperty(value, fieldName4Key);
map.put(k, value);
}
} catch (Exception e) {
throw new IllegalArgumentException("field can't match the key!");
}
}
return map;
}
经测试(main方法里面的时间是测试结果):效率很低,多次调用了beanUtils.getProperty严重降低了方法的效率。因此需要找一个替代的方法,比如直接获得get方法,因此版本二诞生了。
/**
* transfer list into map
* @param list
* @param fieldName4Key
* @return map
*
* @author sherlock
* @date 2016-9-16 12:58:53
*/
public static Map list2Map2(List list, String fieldName4Key,Class c) {
Map map = new HashMap();
if (list != null) {
try {
PropertyDescriptor propDesc = new PropertyDescriptor(fieldName4Key, c);
Method methodGetKey = propDesc.getReadMethod();
for (int i = 0; i < list.size(); i++) {
V value = list.get(i);
@SuppressWarnings("unchecked")
K key = (K) methodGetKey.invoke(list.get(i));
map.put(key, value);
}
} catch (Exception e) {
throw new IllegalArgumentException("field can't match the key!");
}
}
return map;
}
测试结果比较满意,效率上与一般的转换方式差距不大。
也可以通过方法名获得method,因为它们都是先获得方法,效率区别不大,优点是当你需要复杂的规则去组成key或者value的时候,可以调用自定义的方法,更加灵活,示例代码
public static Map list2Map3(List list, String keyMethodName,Class c) {
Map map = new HashMap();
if (list != null) {
try {
Method methodGetKey = c.getMethod(keyMethodName);
for (int i = 0; i < list.size(); i++) {
V value = list.get(i);
@SuppressWarnings("unchecked")
K key = (K) methodGetKey.invoke(list.get(i));
map.put(key, value);
}
} catch (Exception e) {
throw new IllegalArgumentException("field can't match the key!");
}
}
return map;
}
package test;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.beanutils.BeanUtils;
public class ListToMap {
public static class DemoClass{
private Integer id;
private String name;
public DemoClass(){}
public DemoClass(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static Map list2Map1(List list, String fieldName4Key) {
Map map = new HashMap();
if (list != null) {
try {
for (int i = 0; i < list.size(); i++) {
V value = list.get(i);
@SuppressWarnings("unchecked")
K k = (K) BeanUtils.getProperty(value, fieldName4Key);
map.put(k, value);
}
} catch (Exception e) {
throw new IllegalArgumentException("field can't match the key!");
}
}
return map;
}
/**
* transfer list into map
* @param list
* @param fieldName4Key
* @return map
*
* @author sherlock
* @date 2016-9-16 12:58:53
*/
public static Map list2Map2(List list, String fieldName4Key,Class c) {
Map map = new HashMap();
if (list != null) {
try {
PropertyDescriptor propDesc = new PropertyDescriptor(fieldName4Key, c);
Method methodGetKey = propDesc.getReadMethod();
for (int i = 0; i < list.size(); i++) {
V value = list.get(i);
@SuppressWarnings("unchecked")
K key = (K) methodGetKey.invoke(list.get(i));
map.put(key, value);
}
} catch (Exception e) {
throw new IllegalArgumentException("field can't match the key!");
}
}
return map;
}
public static Map list2Map3(List list, String keyMethodName,Class c) {
Map map = new HashMap();
if (list != null) {
try {
Method methodGetKey = c.getMethod(keyMethodName);
for (int i = 0; i < list.size(); i++) {
V value = list.get(i);
@SuppressWarnings("unchecked")
K key = (K) methodGetKey.invoke(list.get(i));
map.put(key, value);
}
} catch (Exception e) {
throw new IllegalArgumentException("field can't match the key!");
}
}
return map;
}
public static Map traditionalWay(List list) {
Map map = new HashMap();
if (list != null) {
for (int i = 0; i < list.size(); i++) {
DemoClass value = list.get(i);
map.put(value.getId(), value);
}
}
return map;
}
public static void main(String[] args) throws Exception{
List list = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
list.add(new DemoClass(i,"aaa"));
}
long start1 = System.nanoTime();
//list2Map1(list,"id"); //2265651285
list2Map2(list,"id",DemoClass.class); //95193405
//list2Map3(list,"getId",DemoClass.class);
//Map map = traditionalWay(list); //75825131
long end1 = System.nanoTime();
System.out.println(end1 - start1);
}
}
list2Map2(...),list2Map3(...)都是可取的,区别是list2Map3(...)比较灵活
对应代码
Map java8map = list.stream().collect(Collectors.toMap(DemoClass::getId, Function.identity()));
1、在元素的方法变更的时候,编译器会报错,提醒程序员更改
1、使用效率太低
10万其中一次结果
46225154
123026843
元素数目越小,差距越大
元素个数0时,取其中一次
6955583
89043721
个人认为大部分场景使用list2Map2(...),list2Map3(...)是足够的,对于一个java bean发生常用属性变更或者方法变更的可能性太低
转载需要注明出处