今天有一个新需求, 是对一个 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 >> listSeriesValueRates(List 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 >>> () {});
- }
这里我们传入的是一个车系 id 集合.
然后继续往下调用:
- public List listSeriesValueRate(final long seriesId) {
- String key = "listSeriesValueRate" + seriesId;
- return managerService.get(key, new Callable > () {@Override public List call() throws Exception {
- Map > valueRateDTOs = listAllSeriesValueRate();
- List dtos = valueRateDTOs.get(seriesId);
- return dtos;
- }
- },
- CommonConstants.ExpiredTime.ONE_DAY);
- }
这里使用了 DCache 去缓存不同的 seriesId 对应的数据, 接下来再看看查询所有车系保值率数据 (listAllSeriesValueRate()):
- private LoadingCache >> cache = CacheBuilder.newBuilder().expireAfterWrite(12, TimeUnit.HOURS).build(new CacheLoader >> () {@Override public Map > load(String k) {
- List valueRateDTOs = Lists.newArrayList();
- List 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 > map = Maps.newHashMap(); //第17行
- GroupUtils.listGroup2Map(valueRateDTOs, map, SeriesValueRateDTO.class, "getSeriesId"); //第18行
- return map;
- }
- });
这里使用了 GuavaCache 去缓存所有的车系保值率数据, 然后这里使用了 GroupUtils 去进行分组, 分组是按照 "getSeriesId" 来获取 seriesId 进行分组. 我们来查看下分组前的数据结构 (代码中第 17 行处查看 debug 数据):
然后再看看分组后的数据结构 (运行完第 18 行数据结果):
很显然, 数据已经进行了分组, 最后看看我们是如何高效率的通过传入的 seriesIds 取值的:
- public List >> listSeriesValueRates() {
- webContext context = WebContext.get();
- List ids = context.getRequiredLongList("seriesIds");
- List >> seriesValueRateDTOs = Lists.newArrayList();
- for (long seriesId: ids) {
- HashMap > map = Maps.newHashMap();
- List dtos = seriesValueRateEntityService.listSeriesValueRate(seriesId);
- map.put(seriesId, dtos);
- seriesValueRateDTOs.add(map);
- }
- return seriesValueRateDTOs;
- }
- public List listSeriesValueRate(final long seriesId) {
- String key = "listSeriesValueRate" + seriesId;
- return managerService.get(key, new Callable > () {@Override public List call() throws Exception {
- Map > valueRateDTOs = listAllSeriesValueRate();
- List 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;
- }
- }
这里直接铺上代码, 其实也很简单, 具体使用规则请参考上面.
- public class GroupUtils {
- private static final Logger LOGGER = LoggerFactory.getLogger(GroupUtils.class);
- /**
- * 分组依赖接口
- */
- public interface GroupBy {
- T groupby(Object obj);
- }
- /**
- *
- * @param colls
- * @param gb
- * @return
- */
- public static final extends Comparable,
- D > Map > group(Collection colls, GroupBy gb) {
- if (colls == null || colls.isEmpty()) {
- LOGGER.info("分组集合不能为空!");
- return null;
- }
- if (gb == null) {
- LOGGER.info("分组依赖接口不能为Null!");
- return null;
- }
- Iterator iter = colls.iterator();
- Map > map = new HashMap > ();
- while (iter.hasNext()) {
- D d = iter.next();
- T t = gb.groupby(d);
- if (map.containsKey(t)) {
- map.get(t).add(d);
- } else {
- List list = new ArrayList();
- 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 void listGroup2Map(List list, Map > map, Class 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 void listGroup2Map(List list, Map > 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 listTmp;
- for (V val: list) {
- key = method.invoke(val);
- listTmp = map.get(key);
- if (null == listTmp) {
- listTmp = new ArrayList();
- map.put((K) key, listTmp);
- }
- listTmp.add(val);
- }
- } catch(Exception e) {
- LOGGER.info("分组失败!");
- }
- }
- }
最后大家可以根据自己的需求来选择改造或使用. 回头发现项目中能学到的东西很多, 记录下来希望以后能够多看看. 2016/12/06
来源: http://www.cnblogs.com/wang-meng/p/6139067.html