1)merge()
我理解这个merge可以废弃了,完全使用conpute代替!!!
// 名字其实很直观:合并数量。 不存在时,当然会追加。
// 与compute的区别:merge接收的是3个参数。 而 compute接收的是2个参数
场景:我通过多个途径获取了物品a,发给客户端前需要合并下数量
package org.example.basic;
import java.util.HashMap;
import java.util.Map;
public class TestMerge {
public static void main(String[] args) {
Map<Integer, Integer> idNumMap = new HashMap<>();
idNumMap.put(1, 10);
idNumMap.put(2, 20);
idNumMap.put(3, 30);
System.out.println(idNumMap);
// 测试存在,则累计
mergeAttr(idNumMap, 1, 30);
System.out.println(idNumMap);
// 测试key不存在,则加入
mergeAttr(idNumMap, 4, 40);
System.out.println(idNumMap);
}
public static Map<Integer, Integer> mergeAttr(Map<Integer, Integer> idNumMap, int id, int num) {
// 注意第3个参数lambda表达式
idNumMap.merge(id, num, Integer::sum);
return idNumMap;
}
}
/*
//原始
{1=10, 2=20, 3=30}
// merge一次后
{1=40, 2=20, 3=30}
// 不存在则插入
{1=40, 2=20, 3=30, 4=40}
*/
例子2:每个等级有个属性加成,加到一起
// 其实跟例子1是一样的,只不过这是真实案例,相当于
// 玩家身上有多个buff,buff1添加移速1,攻击2 buff2添加移速5,暴击10 这样子计算玩家总属
// 性时,就可以把多个buff的效果合并到一起。
package org.example.ch2;
import java.util.HashMap;
import java.util.Map;
public class Main2 {
public static void main(String[] args) {
int[] attribute = new int[]{1, 2, 3, 4, 1, 2};
float[] value = new float[]{1, 1, 1, 1, 1, 1};
Map<Integer, Float> map = new HashMap<>();
for (int i = 0; i < attribute.length; i++) {
map.merge(attribute[i], value[i], (o, n) -> o + n);
}
System.out.println(map);
}
}
/*
{1=2.0, 2=2.0, 3=1.0, 4=1.0}
*/
2)compute方法(存在此key则修改,不存在,则会进行插入)
// 含义是:替换,计算嘛,计算出来一个新的,替换掉旧的。
例子:玩家一下子获得多个道具包,在展示时,需要进行下数量合并:
包1包含:金币100个 黄金 100,
包2包含:金币200个 格斗币 300
那给客户端展示时,不可能这样子铺开展示,而是:展示的金币应该是300而不是出现2个金币,.这时就需要合并下。
package org.example.testMerge;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.List;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<Integer, AwardItem> map = Maps.newHashMap();
map.put(1, new AwardItem(1, 10, 5));
map.put(2, new AwardItem(1, 20, 50));
List<AwardItem> computeRet = compute(map);
System.out.println(computeRet);
}
public static List<AwardItem> compute(Map<Integer, AwardItem> map) {
// 这个记录下合并的中间结果
Map<Integer, AwardItem> awardSnAwardItemMap = Maps.newHashMap();
for (AwardItem item : map.values()) {
awardSnAwardItemMap.compute(item.getSn(), (k, v) -> {
// 没有的以map中的为准,这样子这个awardSnAwardItemMap也会插入一份
if (v == null) {
return item;
}
// 有的,则累加到一起
return new AwardItem(item.getSn(), v.getFreeNum() + item.getFreeNum(), v.getBindNum() + item.getBindNum());
});
}
return Lists.newArrayList(awardSnAwardItemMap.values());
}
}
/*
[AwardItem(sn=1, freeNum=30, bindNum=55)]
*/
例子2:这个其实更简单一点,这个Map中存的是普通类型的Integer
package org.example.basic;
import java.util.HashMap;
import java.util.Map;
public class TestCompute {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("Shoes", 200);
map.put("Bag", 300);
map.put("Pant", 150);
int num = cal(map, "Shoes1");
System.out.println(map);
System.out.println(num);
}
public static int cal(Map<String, Integer> map, String key) {
// 如果key不存在,则会插入这个key,并且对应的value是lambda的返回值
// 如果存在,则把对应的value,修改为返回值
return map.compute(key, (k, v) -> {
if (v == null) {
return -1;
}
return v - 100;
});
}
}
/*
{Pant=150, Shoes1=-1, Bag=300, Shoes=200}
-1
*/
例子3:玩家过这个关卡需要4个小关卡,每个关卡中记录每个人的得分,
这一关通关时,需要合并下之前的分数,其实就可以再次用上compute
例子4:一种merge和compute等价写法 // 可以看出来这2个有点像,但是我可以总结出:感觉merge更适合普通类型,不然怎么merge(相加)呢? conpute则可以用于复杂类型,如:直接处理的是AwardItem
package org.example.basic;
import com.google.common.collect.Maps;
import java.util.Map;
public class Test1 {
public static void main(String[] args) {
Map<Integer, Integer> map = Maps.newHashMap();
map.put(1, 1);
// 方式1(存在key为2的,则把3合并上去,不然就返回3)
map.merge(2, 3, Integer::sum);
// 方式2(用一个新值填补)
merge(map, 2, 3);
System.out.println(map);
}
static public void merge(Map<Integer, Integer> map, int key, int value) {
map.compute(key, (k, v) -> {
if (v == null) {
return value;
}
return v + value;
});
}
}
3)从Map中获取信息时包装类的一个细节 1.用int取值则报异常 2.用Integer取值则是null
package org.example.testmap;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Param p = new Param();
// 异常
int o1 = p.get("1");
// 正常
Integer o2 = p.get("2");
System.out.println(o2); // null
}
static class Param {
private final Map<String, Object> m = new HashMap<>();
public <K> K get(String key) {
return (K) m.get(key);
}
}
}
4)HashMap的computeIfAbsent方法,不存在该key则做个操作(再也不会因为漏写 if xx == null出现空指针的bug了)
// 因此我觉得这个方法是给这个key对应的值一个默认值
public static ShadowLawPrivilege getPrivilege(Role role, String facilityTag, String privilegeGroupTag, String privilegeIndexTag) {
ShadowLawPrivilege shadowLawPrivilege = role.getShadowLawData()
.getFacilityMap().computeIfAbsent(facilityTag, k -> new ShadowLawFacility())
.getPrivilegeGroupMap().computeIfAbsent(privilegeGroupTag, k -> new ShadowLawPrivilegeGroup())
.getPrivilegeMap().computeIfAbsent(privilegeIndexTag, k -> new ShadowLawPrivilege());
return shadowLawPrivilege;
}
5)增强for循环遍历Map // 可以看出很通用,还能遍历数组
// 初始化
Map<Integer, Room> m = Maps.newHashMap();
m.put(1, new Room(11));
// 遍历
for (Integer key : m.keySet()) {
Room r = m.get(key);
System.out.println(r);
}
6)Maps.newHashMap(map)其实是浅拷贝,因为从copy中获取1对应的User并修改,old的也被修改了
package org.example.testHashMap;
import com.google.common.collect.Maps;
import java.util.Map;
import java.util.Objects;
/**
* @author jianan
* @date 2021/7/8 11:58:51
*/
public class TestHashMap {
public static void main(String[] args) {
Map<Integer, User> old = Maps.newHashMap();
old.put(1, new User("a"));
// 修改copy中的值
Map<Integer, User> copy = Maps.newHashMap(old);
User user = copy.get(1);
user.setName("250");
System.out.println(old);
}
private static class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
return Objects.equals(getName(), user.getName());
}
@Override
public int hashCode() {
return Objects.hash(getName());
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
}
/*
{1=User{name='250'}}
*/
7)HashMap作为多返回值(还是Model好,字符串容易写错)
// 其实用Pair和Triple更合适 或者 自定义的Vo,避免使用json这种结构
package org.example;
import java.util.HashMap;
import java.util.Map;
/**
* @author jianan
* @date 2021/7/2 11:22:29
*/
public class TestObject {
public static void main(String[] args) {
Map<String, Object> map = getResult();
int num = (int) map.get("num");
String str = (String) map.get("str");
System.out.println(num + ":" + str);
}
public static Map<String, Object> getResult() {
Map<String, Object> map = Maps.newHashMap();
map.put("num", 1);
map.put("str", "aaa");
return map;
}
}
/*
* 1:aaa
*/
8) LinkedHashMap是根据插入的顺序有序是一致的,HashMap无序
package org.example;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author jianan
* @date 2021/6/24 17:37:59
*/
public class TestLinkedHashMap {
public static void main(String[] args) {
LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("c", 1);
linkedHashMap.put("a", 3);
linkedHashMap.put("b", 2);
linkedHashMap.put("d", 4);
// 和插入顺序保持一致
System.out.println(linkedHashMap);
Map<String, Integer> map = new HashMap<>();
map.put("c", 1);
map.put("a", 3);
map.put("b", 2);
map.put("d", 4);
// 是乱序的
System.out.println(map);
}
}
/*
{c=1, a=3, b=2, d=4}
{a=3, b=2, c=1, d=4}
*/
9)removeIf
1.removeIf之 满足某个条件,则移除指定的key
2.使用场景是匹配队列中满4人开赛) // 如:每一个匹配队列是一个RoomItem
package org.example.testremoveif;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) {
Map<Integer, String> map = new ConcurrentHashMap<>();
map.put(1, "1");
map.put(2, "2");
map.put(55, "55");
map.put(3, "3");
map.put(4, "4");
ScheduledExecutorService schedule = Executors.newScheduledThreadPool(5);
schedule.scheduleAtFixedRate(() -> {
// 满足条件,则移除
map.entrySet().removeIf(entry -> {
Integer key = entry.getKey();
String value = entry.getValue();
if (key < 4) {
System.out.println("移除key=" + key + " value=" + value + "剩余:" + map.size() + " " + Thread.currentThread().getName());
return true;
}
System.out.println(key + " value=" + value + "剩余:" + map.size() + " " + Thread.currentThread().getName());
return false;
});
}, 1, 1, TimeUnit.SECONDS);
}
}
/*
移除key=1 value=1剩余:5 pool-1-thread-1
移除key=2 value=2剩余:4 pool-1-thread-1
移除key=3 value=3剩余:3 pool-1-thread-1
4 value=4剩余:2 pool-1-thread-1
55 value=55剩余:2 pool-1-thread-1
4 value=4剩余:2 pool-1-thread-1
55 value=55剩余:2 pool-1-thread-1
4 value=4剩余:2 pool-1-thread-2
*/
10)只读的HashMap
// 比如:表数据。虽然是Map,但是取出来values后得到的Collection<Xx>其实基本上是有序的。
package org.example.basic;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.util.Map;
public class TestReadOnlyList {
public static void main(String[] args) {
// 原始配置数据
Map<String, Integer> map = Maps.newHashMap();
map.put("1", 111);
// 转化为只读map
ImmutableMap.Builder<String, Integer> builder = ImmutableMap.builder();
builder.putAll(map);
// 最终只读的map
ImmutableMap<String, Integer> itemMap = builder.build();
System.out.println(itemMap.get("1"));
itemMap.putIfAbsent("2", 22);
}
}
/*
111
Exception in thread "main" java.lang.UnsupportedOperationException
at com.google.common.collect.ImmutableMap.put(ImmutableMap.java:326)
at java.base/java.util.Map.putIfAbsent(Map.java:775)
at org.example.basic.TestReadOnlyList.main(TestReadOnlyList.java:22)
*/
11)newIdentityHashMap // 可重复键值对
package org.example.basic;
import com.google.common.collect.Maps;
import java.util.Map;
public class TestReadOnlyList {
public static void main(String[] args) {
Map<Integer, Integer> map = Maps.newIdentityHashMap();
map.put(128, 1);
map.put(128, 1);
map.put(2, 3);
System.out.println(map);
}
}
/*
{128=1, 128=1, 2=3}
*/
12)putIfabsent
看名字就可以看出,不存在时插入,并且返回值是空。
存在的话,就会返回之前的值,也就是说:不会出现覆盖的情况。
static {
Map<Integer, EBuffAttributeType> map = new HashMap<>();
for (EBuffAttributeType type : values()) {
if (map.putIfAbsent(type.attributeType, type) != null) {
log.error("重复的attributeType={}", type.attributeType);
}
}
typeMap = map;
}