• 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

java 将list转换为map 的泛型通用方法

Java基础学习 来源:EasyofUse 2次浏览

将list转换为map

背景:最近使用比较多的mongodb,由于其缺乏表连接的查询,导致我们经常需要将表数据查询到内存中,然后进行匹配连接,组成需要的数据格式,匹配的方式通常是:

list1中有list2需要的字段,于是将list1转换为map,遍历list2,从map中找到对应的数据字段。当面对大量的这样的业务操作的时候,一个个写将list转换为map的小代码段,是非常浪费时间,容易出错且无益的,所以抽时间将这个方法写下来,以便以后使用。

本人在写这个方法的时候,只改进过一次,执行效率上和原始的转换代码效率差距不大了,是可以使用的方法了

现在增加了java8的流的方式的对比,可以供参考

1、首先是list里面的bean 没什么好说的

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;
		}	
	}

2、传统的转换方法

public static Map<Integer, DemoClass> traditionalWay(List<DemoClass> list) {
		Map<Integer, DemoClass> map = new HashMap<Integer, DemoClass>();
		if (list != null) {
			for (int i = 0; i < list.size(); i++) {
				DemoClass value = list.get(i);
				map.put(value.getId(), value);
			}
		}

		return map;
	}

下面来实现通用接口

 

3、由于我们通常需要转换的时候,需要将其中一个属性作为key,整个对象(或者其中一个属性,方法类似,自己去拓展)作为value构成map

 方法名为

 

public static <K, V> Map<K, V> list2Map(List<V> list, String fieldName4Key);

 

4、工程引入jar包,不是所有的jar包都要包含,像dom4j就不需要

5、版本一:我们写这个方法的时候无法获得bean的get方法,首先想到使用内省机制去实现,commons-beanutils提供了获得属性名对应的get方法,代码如下

 

public static <K, V> Map<K, V> list2Map1(List<V> list, String fieldName4Key) {
		Map<K, V> map = new HashMap<K, V>();
		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方法,因此版本二诞生了。

 

6、版本二:

       /**
     * transfer list into map
     * @param list
     * @param fieldName4Key
     * @return map
     * 
     * @author sherlock
     * @date 2016-9-16 12:58:53
     */
    public static <K, V> Map<K, V> list2Map2(List<V> list, String fieldName4Key,Class<V> c) {
        Map<K, V> map = new HashMap<K, V>();
        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 <K, V> Map<K, V> list2Map3(List<V> list, String keyMethodName,Class<V> c) {
        Map<K, V> map = new HashMap<K, V>();
        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;
    }

 

7、以下是整个类,以及测试结果,测试结果在每个方法调用的注释里

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 <K, V> Map<K, V> list2Map1(List<V> list, String fieldName4Key) {
        Map<K, V> map = new HashMap<K, V>();
        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 <K, V> Map<K, V> list2Map2(List<V> list, String fieldName4Key,Class<V> c) {
        Map<K, V> map = new HashMap<K, V>();
        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 <K, V> Map<K, V> list2Map3(List<V> list, String keyMethodName,Class<V> c) {
        Map<K, V> map = new HashMap<K, V>();
        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<Integer, DemoClass> traditionalWay(List<DemoClass> list) {
        Map<Integer, DemoClass> map = new HashMap<Integer, DemoClass>();
        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<DemoClass> 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<Integer,DemoClass> map = traditionalWay(list); //75825131
        long end1 = System.nanoTime();
        
        System.out.println(end1 - start1);
    }
}

list2Map2(…),list2Map3(…)都是可取的,区别是list2Map3(…)比较灵活

8、JAVA8流的方式

对应代码

Map<Integer, DemoClass> java8map = list.stream().collect(Collectors.toMap(DemoClass::getId, Function.identity()));

优势:

1、在元素的方法变更的时候,编译器会报错,提醒程序员更改

劣势:

1、使用效率太低

10万其中一次结果

46225154
123026843

元素数目越小,差距越大

元素个数0时,取其中一次

6955583
89043721

个人认为大部分场景使用list2Map2(…),list2Map3(…)是足够的,对于一个java bean发生常用属性变更或者方法变更的可能性太低

 

转载需要注明出处

 

 


版权声明:本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。
喜欢 (0)