业务场景:
有一批节点,每个节点的字段是是一样的,如下:uid,cmmdtyCode,supplierCode。要求统计各商户下各个cmmdtyCode出现了多少次。样例数据如下:
[
{
"uid":"127437864373237009",
"cmmdtyCode":" 000000000659869748",
"supplierCode":" 0070113914"
},
{
"uid":"127437864373237010",
"cmmdtyCode":" 000000000659869748",
"supplierCode": " 0070113914"
},
{
"uid":”127437864373237011”,
"cmmdtyCode":" 000000000659869749",
"supplierCode":" 0070113914"
},
{
"uid”:”127437864373237012”,
"cmmdtyCode":" 000000000659869748",
"supplierCode": "0070113915"
}
]
预期输出:supplierCode:cmmdtyCode=商品出现次数
实现方法
1)环境说明
本例jdk版本为1.7,代码在testng里面执行
2)数据准备
将前面的样例数据以List>的格式存储起来,代码如下:
import java.util.List;
import java.util.Map;
import org.powermock.modules.testng.PowerMockTestCase;
import org.testng.annotations.BeforeMethod;
import com.beust.jcommander.internal.Lists;
import com.google.common.collect.Maps;
public class TestJ2 extends PowerMockTestCase {
private List> params = Lists.newArrayList();
@BeforeMethod
public void initMethod() {
Map item = Maps.newHashMap();
item.put("uid", "127437864373237009");
item.put("cmmdtyCode", "000000000659869748");
item.put("supplierCode", "0070113914");
params.add(item);
Map item2 = Maps.newHashMap();
item2.put("uid", "127437864373237010");
item2.put("cmmdtyCode", "000000000659869748");
item2.put("supplierCode", "0070113914");
params.add(item2);
Map item3 = Maps.newHashMap();
item3.put("uid", "127437864373237011");
item3.put("cmmdtyCode", "000000000659869749");
item3.put("supplierCode", "0070113914");
params.add(item3);
Map item4 = Maps.newHashMap();
item4.put("uid", "127437864373237012");
item4.put("cmmdtyCode", "000000000659869748");
item4.put("supplierCode", "0070113915");
params.add(item4);
}
}
3)实现方法1
// 一般计算方法
@Test
public void execute() {
// 每个商户下,不同商品出现的次数
Map numMap = Maps.newHashMap();
for (Map item : params) {
Integer num = MapUtils.getInteger(numMap, getKey(item));
if (num == null) {
num = 1;
} else {
num += 1;
}
numMap.put(getKey(item), num);
}
printResult(numMap);
}
// 拼接业务主键
private String getKey(Map item) {
return MapUtils.getString(item, "supplierCode") + ":" + MapUtils.getString(item, "cmmdtyCode");
}
// 打印计算结果
private void printResult(Map numMap) {
for (Map.Entry entry : numMap.entrySet()) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
}
输出结果:
0070113914:000000000659869748=2
0070113914:000000000659869749=1
0070113915:000000000659869748=1
耗时:8ms
4)实现方法2
// 改进计算方法
/**
* 在jdk1.7(含)以下的版本中,普通Map类没有putIfAbsent,只有ConcurrentMap的子类才有,jdk8(含)之后,普通类也提供了该方法
* 由于作者本人机器使用的是JDK1.7,故使用ConcurrentMap类进行演示,实际上,在单线程计算中,普通map类的效率要高于ConcurrentMap
*/
@Test
public void execute2() {
ConcurrentMap numMap = Maps.newConcurrentMap();
for (Map item : params) {
// 如果集合中不包括key,则写入默认值1,并返回null;否则直接返回集合中key对应的value对象的引用
AtomicInteger oldValue = numMap.putIfAbsent(getKey(item), new AtomicInteger(1));
if (oldValue != null) {
// 对象数值+1
oldValue.incrementAndGet();// 利用map存储的是对象的引用,直接对象的值,不需要重新写回map
}
}
printResult(numMap);
}
// 拼接业务主键
private String getKey(Map item) {
return MapUtils.getString(item, "supplierCode") + ":" + MapUtils.getString(item, "cmmdtyCode");
}
private void printResult(Map numMap) {
for (Map.Entry entry : numMap.entrySet()) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
}
输出结果:
0070113914:000000000659869749=1
0070113914:000000000659869748=2
0070113915:000000000659869748=1
耗时:11ms
5)实现方法3
// 分组计算方法
@Test
public void execute3() {
HashMultimap> group = HashMultimap.create();
// 将所有节点分组,cmmdtyCode和supplierCode相同的item分入一组
for (Map item : params) {
group.put(getKey(item), item);
}
Map numMap = Maps.newHashMap();
// 统计每一组的元素个数
for (String key : group.keySet()) {
numMap.put(key, group.get(key).size());
}
printResult(numMap);
}
// 拼接业务主键
private String getKey(Map item) {
return MapUtils.getString(item, "supplierCode") + ":" + MapUtils.getString(item, "cmmdtyCode");
}
// 打印计算结果
private void printResult(Map numMap) {
for (Map.Entry entry : numMap.entrySet()) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
}
该方法引入了google API,具体引用路径为:
import com.google.common.collect.HashMultimap;
输出结果:
0070113914:000000000659869748=2
0070113914:000000000659869749=1
0070113915:000000000659869748=1
耗时:43ms
6)增加测试数据
@BeforeMethod
public void initMethod() {
for (int i = 0; i < 100; i++) {
Map itemR = Maps.newHashMap();
itemR.put("uid", i);
itemR.put("cmmdtyCode", "000000000659869748");
itemR.put("supplierCode", "0070113915");
params.add(itemR);
}
for (int j = 0; j < 100; j++) {
Map itemR = Maps.newHashMap();
itemR.put("uid", j);
itemR.put("cmmdtyCode", "000000000659869749");
itemR.put("supplierCode", "0070113915");
params.add(itemR);
}
for (int j = 0; j < 100; j++) {
Map itemR = Maps.newHashMap();
itemR.put("uid", j);
itemR.put("cmmdtyCode", "000000000659869748");
itemR.put("supplierCode", "0070113914");
params.add(itemR);
}
}
耗时如下:
数据量
10
100
1000
方法1耗时
11ms
8ms
19ms
方法2耗时
9ms
11ms
18ms
方法3耗时
45ms
40ms
59ms
总结:
方法1耗时最少,且较为常见,推荐