双列集合使用

总结

  1. TreeMap添加元素的时候,键不需要重写hashCode和equals方法,压根没用到hashCode和equals方法。使用红黑树规则添加的元素,是使用Comparable来比较key是否相等,返回0表示相等,自定义对象必须实现这个接口。
  2. HashMap是哈希表结构,JDK8开始由数组,链表,红黑树组成。虽然有红黑树,但HashMap的底层是使用哈希值和equals方法来创建红黑树的,所以不需要实现Comparable接口。
  3. HashMap添加元素的时候,需要重写hashCode和equals方法,它是根据key的hash值决定添加元素的位置,需要使用hashCode和equals方法,不然会添加重复的key。
  4. HashMap和TreeMap使用put添加元素时会覆盖key相同的value值,返回旧值;使用putIfAbsent方法添加元素则不会覆盖旧值。
  5. TreeMap和HashMap一般而言,HashMap的效率要更高。
  6. 如何选择
    1. 默认:HashMap(效率最高)
    2. 如果要保证存取顺序一样:LinkedHashMap
    3. 如果要进行排序:TreeMap

1、特点:

  • 双列集合一次需要存一对数据,分别为键和值
  • 键不能重复,值可以重复
  • 键和值是一一对应的,每一个键只能找到自己对应的值
  • 键 + 值 这个整体我们称之为”键值对“ 或者”键值对对象“,在Java中叫做”Entry对象“

2、Map的常见API

Map是双列集合的顶层接口,它的功能是全部双列集合都可以继承使用的

方法名称说明
V put(K key, V value)添加元素
V remove(Object key)根据删除键值对元素
void clear()移除所有的键值对元素
boolean containsKey(Object key)判断集合是否包含指定的键
boolean containsValue(Object value)判断集合是否包含是否包含指定的值
boolean isEmpty()判断集合是否为空
int size()集合的长度,也就是集合中键值对的个数
public class A01_MapDemo1 {
    public static void main(String[] args) {
        /*
        V put(K key, V value)                       添加元素
        V remove(Object key)                        根据删除键值对元素
        void clear()                                移除所有的键值对元素
        boolean containsKey(Object key)             判断集合是否包含指定的键
        boolean containsValue(Object value)         判断集合是否包含是否包含指定的值
        boolean isEmpty()                           判断集合是否为空
        int size()                                  集合的长度,也就是集合中键值对的个数
        */

        // 1.创建Map集合的对象
        Map<String, String> map = new HashMap<>();

        // 2.添加元素
        // put方法的细节:
        // 添加/覆盖
        // 在添加数据的时候,如果键不存在,那么直接把键值对对象添加到map集合当中,方法返回null
        // 在添加数据的时候,如果键存在,那么会将原有的键值对进行覆盖,并将被覆盖的值返回


        String value1 = map.put("郭靖", "黄蓉");
        System.out.println("value1 = " + value1);; // null
        map.put("韦小宝", "沐剑屏");
        map.put("尹志平", "小龙女");

        String value2 = map.put("郭靖", "小鱼儿");
        System.out.println("value2 = " + value2);; // 黄蓉

        // 判断是否包含key
        boolean keyResult = map.containsKey("郭靖");
        System.out.println("keyResult = " + keyResult); // true

        // 判断是否包含value
        boolean valueResult = map.containsValue("小鱼儿");
        System.out.println("valueResult = " + valueResult); // true
        
        // 判断集合是否为空
        boolean result1 = map.isEmpty(); // true

        // 集合的长度
        int size = map.size();
        System.out.println(size); // 3
        
        // 3.打印集合
        System.out.println(map); // {韦小宝=沐剑屏, 尹志平=小龙女, 郭靖=小鱼儿}

        // 删除
        String result = map.remove("郭靖");
        System.out.println("result = " + result); // 小鱼儿
        System.out.println(map); // {韦小宝=沐剑屏, 尹志平=小龙女}

        // 清空
        map.clear();
        System.out.println(map); // {}
    }
}

3、Map集合遍历

  1. 第一种(键找值)

    public class A02_MapDemo2 {
        public static void main(String[] args) {
            // Map集合的第一种遍历方式
    
    
            // 1.创建Map集合对象
            Map<String, String> map = new HashMap<>();
    
            // 2.添加元素
            map.put("郭靖", "黄蓉");
            map.put("韦小宝", "沐剑屏");
            map.put("尹志平", "小龙女");
    
            // 3.通过键找值
            // 3.1获取所有的键,把这些键放到一个单列集合当中
            Set<String> keys = map.keySet();
            for (String key : keys) {
                // 3.3利用map集合中的键来获取对应的值
                String value = map.get(key);
                System.out.println(key + " = " + value);
            }
    
        }
    } 
    
  2. 第二种(键值对)

    public class A03_MapDemo3 {
        public static void main(String[] args) {
            // Map集合的第二种遍历方式(键值对)
    
    
            // 1.创建Map集合对象
            Map<String, String> map = new HashMap<>();
    
            // 2.添加元素
            map.put("郭靖", "黄蓉");
            map.put("韦小宝", "沐剑屏");
            map.put("尹志平", "小龙女");
    
            // 3.通过键值对对象进行遍历
            // 3.1通过entrySet方法获取所有的键值对对象,返回一个set集合
            Set<Map.Entry<String, String>> entries = map.entrySet();
            // 3.2遍历entries集合,得到里面的每一个键值对对象
            for (Map.Entry<String, String> entry : entries) {
                String key = entry.getKey();
                String value = entry.getValue();
                System.out.println(key + " = " + value);
            }
        }
    }
    
  3. 第三种(Lambda表达式)

    public class A04_MapDemo4 {
        public static void main(String[] args) {
            // Map集合的第二种遍历方式(Lambda表达式)
    
    
            // 1.创建Map集合对象
            Map<String, String> map = new HashMap<>();
    
            // 2.添加元素
            map.put("郭靖", "黄蓉");
            map.put("韦小宝", "沐剑屏");
            map.put("尹志平", "小龙女");
    
            // 3.利用lambda表达式进行遍历
            // 底层:
            // forEach其实就是利用entrySet方法进行遍历,依次得到每一个键和值
            map.forEach(new BiConsumer<String, String>() {
                @Override
                public void accept(String key, String value) {
                    System.out.println(key + " = " + value);
                }
            });
            System.out.println("-----------------------------");
    
            // 简写
            map.forEach((key, value) -> System.out.println(key + " = " + value));
        }
    }
    

4、HashMap

4.1、特点
  1. HashMap是Map里面的一个实现类
  2. 没有额外需要学习的特有方法,直接使用Map里面的方法就可以了
  3. 特点都是由键决定的:不重复、无索引、无序:不会按照key进行排序
  4. HashMap跟HashSet底层原理是一模一样的,都是哈希表结构
  5. 依赖hashcode方法和equals方法保证键的唯一
  6. 如果键存储的是自定义对象,需要重写hashCode和equals方法,反之不用
4.2、案例
public class A06_HashMapDemo2 {
    public static void main(String[] args) {
        /*
        某个班级80名学生,现在需要组成秋游活动
        班长提供了四个景点依次是(A,B,C,D)
        每个学生只能选择一个景点,请统计出最终哪个景点想去的人数最多
         */

        // 1.需要先让学生投票
        // 定义一个数组,存储4个景点
        String[] arr = {"A", "B", "C", "D"};
        // 利用随机数模拟80个同学,并把投票结果存储起来
        ArrayList<String> list = new ArrayList<>();
        Random r = new Random();
        for (int i = 0; i < 80; i++) {
            int index = r.nextInt(arr.length);
            list.add(arr[index]);
        }

        // 2.如果要统计的东西比较多,不方便使用计数器思想
        // 我们可以定义map集合,利用集合进行统计
        HashMap<String, Integer> hm = new HashMap<>();
        for (String name : list) {
            // 判断当前景点在map集合当中是否存在
            if (hm.containsKey(name)) {
                // 存在
                // 先获取当前景点已经被投票的次数
                int count = hm.get(name);
                // 表示当前景点又投了一次
                count++;
                // 把新的次数再次添加到集合当中
                hm.put(name,count);
            } else {
                // 不存在
                hm.put(name,1);
            }
        }
        System.out.println(hm);

        // 3.求最大值
        int max = 0;
        Set<Map.Entry<String, Integer>> entries = hm.entrySet();
        for (Map.Entry<String, Integer> entry : entries) {
            int count = entry.getValue();
            if (count > max) {
                max = count;
            }
        }
        System.out.println(max);

        // 4.判断哪个景点的次数跟最大值一样,打印出来
        for (Map.Entry<String, Integer> entry : entries) {
            Integer count = entry.getValue();
            if (count == max) {
                System.out.println("最大值:" + entry.getKey());
            }
        }
    }
}

5、LinkedHashMap

5.1、特点
  • 由键决定:不重复、无索引、有序:保证存储和取出的元素顺序一致
  • 原理:底层数据结构依然是哈希表,只是每个键值对元素又额外多了一个双链表的机制记录存储的顺序
5.2、案例
public class A07_LinkedHashMapDemo3 {
    public static void main(String[] args) {
        // 1.创建集合
        LinkedHashMap<String, Integer> lhm = new LinkedHashMap<>();
        // 2.添加元素,有序指的时存取的顺序是一样的
        lhm.put("a",123);
        lhm.put("d",567);
        lhm.put("c",456);
        lhm.put("b",345);
        
        // 3.打印集合
        System.out.println(lhm); // {a=123, d=567, c=456, b=345}
    }
}

6、TreeMap

6.1、特点
  • TreeMap跟TreeSet底层原理一样,都是红黑树结构的
  • 由键决定特性:不重复,无索引,可排序
  • 注意:默认按照键从小到大进行排序,就是升序,也可以自己规定键的排序顺序

代码书写两种排序规则:

  • 实现Comparable接口,指定比较规则
  • 创建集合时传递Comparator比较器对象,指定比较规则
6.2、案例1
public class A01_TreeMapDemo1 {
    public static void main(String[] args) {
        /*
        TreeMap集合:基本应用
        需求1:
            键:整数表示id
            值:字符串表示商品名称
            要求:按照id的升序排列、按照id的降序排列
        */

        // 1.创建集合对象
        // 默认情况下都是按照升序排列的
        // String 按照字母在ASCII码表中对应的数字升序进行排列
        // abcde...
        TreeMap<Integer, String> tm = new TreeMap<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                // 根据key倒叙排序
                // o1:表示当前要添加的元素
                // o2:表示已经在红黑树中存在的元素
                return o2 - o1;
            }
        });

        // 2.添加元素
        tm.put(2,"可口可乐");
        tm.put(4,"百事可乐");
        tm.put(5,"奥利奥");
        tm.put(3,"江小白");
        tm.put(1,"康师傅");

        // 3.打印集合
        System.out.println(tm); // {5=奥利奥, 4=百事可乐, 3=江小白, 2=可口可乐, 1=康师傅}
    }
}
6.3、案例2:
  • Student.java

    public class Student implements Comparable<Student>{
        private String name;
        private int age;
    
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        /**
         * 获取
         * @return name
         */
        public String getName() {
            return name;
        }
    
        /**
         * 设置
         * @param name
         */
        public void setName(String name) {
            this.name = name;
        }
    
        /**
         * 获取
         * @return age
         */
        public int getAge() {
            return age;
        }
    
        /**
         * 设置
         * @param age
         */
        public void setAge(int age) {
            this.age = age;
        }
    
        public String toString() {
            return "Student{name = " + name + ", age = " + age + "}";
        }
    
        @Override
        public int compareTo(Student o) {
            // 要求:按照学生年龄的升序排序,年龄一样按照姓名的字母排列,同姓名同年龄的视为同一人
    
            // this:表示当前要添加的元素
            // o:表示已经在红黑树中存在的元素
    
            // 返回值:
            // 负数:表示当前要添加的元素是小的,存左边
            // 正数:表示当前要添加的元素是大的,存右边
            // 0:表示当前要添加的元素已经存在,舍弃
    
            int i = this.getAge() - o.getAge();
            i = i == 0 ? this.getName().compareTo(o.getName()) : i;
            return i;
        }
    }
    
  • A02_TreeMapDemo2.java

    public class A02_TreeMapDemo2 {
        public static void main(String[] args) {
                /*
            TreeMap集合:基本应用
            需求2:学生对象
            值:籍贯
            要求:按照学生年龄的升序排序,年龄一样按照姓名的字母排列,同姓名同年龄的视为同一人
         */
    
            // 1.创建集合
            TreeMap<Student, String> tm = new TreeMap<>();
    
            // 2.创建三个学生对象
            Student s1 = new Student("zhangsan", 23);
            Student s2 = new Student("lisi", 24);
            Student s3 = new Student("wangwu", 25);
    
            // 3.添加元素
            tm.put(s1, "江苏");
            tm.put(s2, "天津");
            tm.put(s3, "北京");
    
            // 4.打印集合
            System.out.println(tm);
        }
    }
    
6.4、案例3:
public class A03_TreeMapDemo3 {
    public static void main(String[] args) {
        /*需求:
            字符串:"adbadadgadbabdadada"
            请统计字符串中每个字符出现的次数,并按照以下格式输出
            输出结果:
            a(5)b(4)c(3)d(2)e(1)

            新的统计思想:利用map集合进行统计

            如果题目中没有要求对结果进行排序,默认使用HashMap,效率高
            如果题目中要求对结果进行排序,使用TreeMap

            键:表示要统计的内容
            值:表示次数

         */

        // 1.定义字符串
        String s = "adbadadgadbabdadada";

        // 2.创建集合
        TreeMap<Character, Integer> tm = new TreeMap<>();

        // 3.遍历字符串得到里面的每一个字符
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            // 拿着c到集合中判断是否存在
            // 存在,表示当前字符又出现了一次
            // 不存在,表示当前字符是第一次出现
            if (tm.containsKey(c)) {
                // 存在
                // 先把已经出现的次数拿出来
                int count = tm.get(c);
                // 当前字符又出现了一次
                count++;
                // 把自增之后的结果再添加到集合当中
                tm.put(c, count);
            } else {
                // 不存在
                tm.put(c, 1);
            }
        }

        // 4.遍历集合,并按照指定的格式进行拼接
        // a(5)b(4)c(3)d(2)e(1)
        // StringBuilder sb = new StringBuilder();
        // tm.forEach((key, value) -> sb.append(key).append("(").append(value).append(")"));

        StringJoiner sj = new StringJoiner("","","");
        tm.forEach((key, value) -> sj.add(key + "").add("(").add(value + "").add(")"));

        System.out.println(sj);
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值