前言

今天有一个新需求, 是对一个List进行分组, 于是便百度到一些可用的代码以及我们项目使用的一些tools, 在这里总结下方便以后查阅.

一: 需求

现在我们一个数据库表t_series_value_rate存储的是每个汽车对应的保值率. 其中一个车系id可以对应多条数据.表内容部分截取如下:

其中series_id是车系id, car_year代表这个车的年限. 比如说车系id为1的车1年的保值率为81.5%, 2年的保值率为73.7%.

那么现在我需要传递过来一个series_id list去查询出相应的数据, 我们是对数据库表t_series_value_rate查询所有做了缓存的, 如果我们对传入的series_id list进行遍历的话势必会很慢. 所以如果能够根据series_id进行分组的话, 那么效率就会高的多.

二: 代码示例

对外暴漏的API接口, 方便别的项目调用:

public List<HashMap<Long, List<SeriesValueRateDTO>>> listSeriesValueRates(List<Long> seriesIds) throws Exception {
ApiResponse response = httpGet("/api/server/series-value-rates/list-series-value-rates.htm?seriesIds=" + Joiner.on(",").skipNulls().join(seriesIds));
return JSON.parseObject(response.getJsonObject().get("data").toString(), new TypeReference<List<HashMap<Long, List<SeriesValueRateDTO>>>>(){});
}

这里我们传入的是一个车系id集合.

然后继续往下调用:

public List<SeriesValueRateDTO> listSeriesValueRate(final long seriesId) {
String key = "listSeriesValueRate" + seriesId;
return managerService.get(key, new Callable<List<SeriesValueRateDTO>>() {
@Override
public List<SeriesValueRateDTO> call() throws Exception {
Map<Long, List<SeriesValueRateDTO>> valueRateDTOs = listAllSeriesValueRate();
List<SeriesValueRateDTO> dtos = valueRateDTOs.get(seriesId);
return dtos;
}
}, CommonConstants.ExpiredTime.ONE_DAY);
}

这里使用了DCache去缓存不同的seriesId对应的数据, 接下来再看看查询所有车系保值率数据(listAllSeriesValueRate()):

private LoadingCache<String, Map<Long, List<SeriesValueRateDTO>>> cache = CacheBuilder.newBuilder()
.expireAfterWrite(12,TimeUnit.HOURS)
.build(new CacheLoader<String, Map<Long, List<SeriesValueRateDTO>>>() {
@Override
public Map<Long, List<SeriesValueRateDTO>> load(String k) {
List<SeriesValueRateDTO> valueRateDTOs = Lists.newArrayList();
List<SeriesValueRateEntity> entities = seriesValueRateEntityDao.findAll(SeriesValueRateEntity.Fields.seriesId.notNull());
for (SeriesValueRateEntity entity : entities) {
SeriesValueRateDTO dto = new SeriesValueRateDTO();
dto.setSeriesId(entity.getSeriesId());
dto.setCarYear(entity.getCarYear());
dto.setValueRate(entity.getValueRate());
valueRateDTOs.add(dto);
} //按照seriesId进行分组
Map<Long, List<SeriesValueRateDTO>> map = Maps.newHashMap(); //第17行
GroupUtils.listGroup2Map(valueRateDTOs, map, SeriesValueRateDTO.class, "getSeriesId");//第18行 return map;
}
});

这里使用了GuavaCache去缓存所有的车系保值率数据, 然后这里使用了GroupUtils去进行分组, 分组是按照"getSeriesId"来获取seriesId进行分组. 我们来查看下分组前的数据结构(代码中第17行处查看debug数据):



然后再看看分组后的数据结构(运行完第18行数据结果):

很显然, 数据已经进行了分组, 最后看看我们是如何高效率的通过传入的seriesIds取值的:

public List<HashMap<Long, List<SeriesValueRateDTO>>> listSeriesValueRates() {
WebContext context = WebContext.get();
List<Long> ids =context.getRequiredLongList("seriesIds");
List<HashMap<Long, List<SeriesValueRateDTO>>> seriesValueRateDTOs = Lists.newArrayList();
for (long seriesId : ids) {
HashMap<Long, List<SeriesValueRateDTO>> map = Maps.newHashMap();
List<SeriesValueRateDTO> dtos = seriesValueRateEntityService.listSeriesValueRate(seriesId);
map.put(seriesId, dtos);
seriesValueRateDTOs.add(map);
} return seriesValueRateDTOs;
} public List<SeriesValueRateDTO> listSeriesValueRate(final long seriesId) {
String key = "listSeriesValueRate" + seriesId;
return managerService.get(key, new Callable<List<SeriesValueRateDTO>>() {
@Override
public List<SeriesValueRateDTO> call() throws Exception {
Map<Long, List<SeriesValueRateDTO>> valueRateDTOs = listAllSeriesValueRate();
List<SeriesValueRateDTO> dtos = valueRateDTOs.get(seriesId);
return dtos;
}
}, CommonConstants.ExpiredTime.ONE_DAY);
}

这里再放上SeriesValueRateDTO:

public class SeriesValueRateDTO {
/**
* 车系id
*/
private long seriesId;
/**
* 保值率
*/
private Double valueRate;
/**
* 车辆年限
*/
private int carYear; public long getSeriesId() {
return seriesId;
} public void setSeriesId(long seriesId) {
this.seriesId = seriesId;
} public Double getValueRate() {
return valueRate;
} public void setValueRate(Double valueRate) {
this.valueRate = valueRate;
} public int getCarYear() {
return carYear;
} public void setCarYear(int carYear) {
this.carYear = carYear;
}
}

三: 分组工具类GroupUtils

这里直接铺上代码, 其实也很简单, 具体使用规则请参考上面.

public class GroupUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(GroupUtils.class);
/**
* 分组依赖接口
*/
public interface GroupBy<T> {
T groupby(Object obj);
} /**
*
* @param colls
* @param gb
* @return
*/
public static final <T extends Comparable<T>, D> Map<T, List<D>> group(Collection<D> colls, GroupBy<T> gb) {
if (colls == null || colls.isEmpty()) {
LOGGER.info("分组集合不能为空!");
return null;
}
if (gb == null) {
LOGGER.info("分组依赖接口不能为Null!");
return null;
}
Iterator<D> iter = colls.iterator();
Map<T, List<D>> map = new HashMap<T, List<D>>();
while (iter.hasNext()) {
D d = iter.next();
T t = gb.groupby(d);
if (map.containsKey(t)) {
map.get(t).add(d);
} else {
List<D> list = new ArrayList<D>();
list.add(d);
map.put(t, list);
}
}
return map;
}
/**
* 将List<V>按照V的methodName方法返回值(返回值必须为K类型)分组,合入到Map<K, List<V>>中<br>
* 要保证入参的method必须为V的某一个有返回值的方法,并且该返回值必须为K类型
*
* @param list
* 待分组的列表
* @param map
* 存放分组后的map
* @param clazz
* 泛型V的类型
* @param methodName
* 方法名
*/
public static <K, V> void listGroup2Map(List<V> list, Map<K, List<V>> map, Class<V> clazz, String methodName) {
// 入参非法行校验
if (null == list || null == map || null == clazz) {
LOGGER.info("CommonUtils.listGroup2Map 入参错误,list:" + list + " ;map:" + map + " ;clazz:" + clazz + " ;methodName:" + methodName);
return;
} // 获取方法
Method method = getMethodByName(clazz, methodName);
// 非空判断
if (null == method) {
return;
} // 正式分组
listGroup2Map(list, map, method);
}
/**
* 根据类和方法名,获取方法对象
*
* @param clazz
* @param methodName
* @return
*/
public static Method getMethodByName(Class<?> clazz, String methodName) {
Method method = null;
// 入参不能为空
if (null == clazz) {
LOGGER.info("GroupUtils.getMethodByName 入参错误,clazz:" + clazz + " ;methodName:" + methodName);
return method;
} try {
method = clazz.getDeclaredMethod(methodName);
} catch (Exception e) {
LOGGER.info("类获取方法失败!");
} return method;
}
/**
* 将List<V>按照V的某个方法返回值(返回值必须为K类型)分组,合入到Map<K, List<V>>中<br>
* 要保证入参的method必须为V的某一个有返回值的方法,并且该返回值必须为K类型
*
* @param list
* 待分组的列表
* @param map
* 存放分组后的map
* @param method
* 方法
*/
@SuppressWarnings("unchecked")
public static <K, V> void listGroup2Map(List<V> list, Map<K, List<V>> map, Method method) {
// 入参非法行校验
if (null == list || null == map || null == method) {
LOGGER.info("GroupUtils.listGroup2Map 入参错误,list:" + list + " ;map:" + map + " ;method:" + method);
return;
} try {
// 开始分组
Object key;
List<V> listTmp;
for (V val : list) {
key = method.invoke(val);
listTmp = map.get(key);
if (null == listTmp) {
listTmp = new ArrayList<V>();
map.put((K) key, listTmp);
}
listTmp.add(val);
}
} catch (Exception e) {
LOGGER.info("分组失败!");
}
}
}

最后大家可以根据自己的需求来选择改造或使用. 回头发现项目中能学到的东西很多, 记录下来希望以后能够多看看. 2016/12/06 http://www.cnblogs.com/wang-meng/

[Java Collection]List分组之简单应用.的更多相关文章

  1. java Collection中的排序问题

    java Collection中的排序问题 这里讨论list.set.map的排序,包括按照map的value进行排序. 1)list排序 list排序可以直接采用Collections的sort方法 ...

  2. JAVA 集合 List 分组的两种方法

    CSDN日报20170219--<程序员的沟通之痛> [技术直播]揭开人工智能神秘的面纱 程序员1月书讯 云端应用征文大赛,秀绝招,赢无人机! JAVA 集合 List 分组的两种方法 2 ...

  3. Java Collection开发技巧

    Java Collection(集合) 集合中的一些技巧: 通过Collections类的静态方法,可以对集合进行一些操作 1 java.util.List<Integer> number ...

  4. java基础学习02(简单的java程序)

    简单的java程序 一.完成的目标 1. 理解java程序的基本组成 2. 如何对程序代码进行注释 3. java标识符的命名规则 4. 了解java中的关键字 5. 使用java定义变量或声明变量 ...

  5. Java设计模式(一) 简单工厂模式不简单

    摘要:本文介绍了简单工厂模式的概念,优缺点,实现方式,以及结合Annotation和反射的改良方案(让简单工厂模式不简单).同时介绍了简单工厂模式(未)遵循的OOP原则.最后给出了简单工厂模式在JDB ...

  6. java中Color类的简单总结

    java中Color类的简单总结 1.颜色的常识 任何颜色都是由三原色组成(RGB),JAVA中支持224为彩色,即红绿蓝分量取值 介于0-255之间(8位表示) 2.Color类中的常量 publi ...

  7. Java Collection Framework概述

    文章出自:听云博客 Collection概述 Java collection是java提供的工具包,包含了常用的数据结构:集合.链表.队列.栈.数组.映射等. Java集合主要可以划分为4个部分:Li ...

  8. Java Collection好文章

    Java Collection好文章 http://my.oschina.net/xiaomaoandhong/blog/78394

  9. spring 第一篇(1-1):让java开发变得更简单(下)

    切面(aspects)应用 DI能够让你的软件组件间保持松耦合,而面向切面编程(AOP)能够让你捕获到在整个应用中可重用的组件功能.在软件系统中,AOP通常被定义为提升关注点分离的一个技术.系统由很多 ...

随机推荐

  1. XSS

    XSS的含义 XSS(Cross Site Scripting)即跨站脚本.跨站的主要内容是在脚本上. 跨站脚本 跨站脚本的跨,体现了浏览器的特性,可以跨域.所以也就给远程代码或者第三方域上的代码提供 ...

  2. RxJS + Redux + React = Amazing!(译一)

    今天,我将Youtube上的<RxJS + Redux + React = Amazing!>翻译(+机译)了下来,以供国内的同学学习,英文听力好的同学可以直接看原版视频: https:/ ...

  3. [BOT] 一种android中实现“圆角矩形”的方法

    内容简介 文章介绍ImageView(方法也可以应用到其它View)圆角矩形(包括圆形)的一种实现方式,四个角可以分别指定为圆角.思路是利用"Xfermode + Path"来进行 ...

  4. JavaScript中Math对象的方法介绍

    1.比较最值方法 比较最值有两种方法,max() 和 min() 方法. 1.1 max() 方法,比较一组数值中的最大值,返回最大值. var maxnum = Math.max(12,6,43,5 ...

  5. ExtJS 4.2 组件介绍

    目录 1. 介绍 1.1 说明 1.2 组件分类 1.3 组件名称 1.4 组件结构 2. 组件的创建方式 2.1 Ext.create()创建 2.2 xtype创建 1. 介绍 1.1 说明 Ex ...

  6. 为.NET Core项目定义Item Template

    作为这个星球上最强大的IDE,Visual Studio不仅仅提供了很多原生的特性,更重要的是它是一个可定制的IDE,比如自定义Project Template和Item Template就是一个非常 ...

  7. Swift enum(枚举)使用范例

    //: Playground - noun: a place where people can play import UIKit var str = "Hello, playground& ...

  8. 【算法】C语言实现数组的动态分配

    C语言实现数组的动态分配 作者:白宁超 2016年10月27日20:13:13 摘要:数据结构和算法对于编程的意义不言而喻,具有指导意义的.无论从事算法优化方向研究,还是大数据处理,亦或者网站开发AP ...

  9. WebApi返回Json格式字符串

    WebApi返回json格式字符串, 在网上能找到好几种方法, 其中有三种普遍的方法, 但是感觉都不怎么好. 先贴一下, 网上给的常用方法吧. 方法一:(改配置法) 找到Global.asax文件,在 ...

  10. 获取打开的Word文档

    using Word = Microsoft.Office.Interop.Word; int _getApplicationErrorCount=0; bool _isMsOffice = true ...