[HashMap] 1.merge 2.compute 3.包装类小坑 4.computeIfAbsent 5.LinkedHashMap 6.removeIf 7.ImmutableMap 8.

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值