Java进阶(第十一期):集合进阶篇(Map系列) 之 双列集合 HashMap & TreeMap & linkedHashMap 、 可变参数 、Collections结合工具类 、集合综合案例

2024年2月14日 情人节

一、双列集合的特点

在这里插入图片描述

二、Map集合常见API

在这里插入图片描述

2.1 代码演示:
public class MapAPI {
    public static void main (String[] LiuJinTao) {
        // 创建双列集合
        Map<String, String> m = new HashMap<>();

        // 1、Map 接口中的 put 方法
                // put 方法的细节:
                        // - 在添加数据的时候,如果键不存在,那么直接把键值对对象添加到map集合中,方法返回值为 null
                        // - 再添加数据的时候,如果键是存在的,那么会把原有的键值对对象覆盖,会把被覆盖的值进行返回
        m.put("张三", "二十三");
        m.put("李四", "二十四");
        m.put("王五", "二十五");
        m.put("张三", "23");
        System.out.println(m); // 李四=二十四, 张三=23, 王五=二十五} Map集合去重 → 后来者覆盖前者

        // 2、Map 接口中的 remove 方法
        String removeResult= m.remove("张三");
        System.out.println(removeResult);   // 23 返回值为被删除指定的键的值

        // 3、Map 接口中的 clear 方法
        // m.clear();
        // System.out.println(m);              // {} 返回一个空的集合



        // 4、Map 接口中的 containsKey 方法
        boolean isContainsKey = m.containsKey("李四");
        System.out.println(isContainsKey);      // true  集合中包含了李四


        // 5、 Map 接口中的 containsValue 方法
        boolean  isContainsValue= m.containsValue("二十三");
        System.out.println(isContainsValue);    // false   集合中不包含二十三这个值的键值对对象

        // 6、Map 接口中的 isEmpty 方法
        boolean isEmptyResult = m.isEmpty();
        System.out.println(isEmptyResult);      // false   集合是否为空


        // 7、Map 集合中的 size 方法
        int sizeResult = m.size();
        System.out.println(sizeResult);         // 2   返回集合的长度大小
        
    }

三、Map 集合的 三种 遍历方式

代码示例:
public class MapTraversingMessage {
    /**
     * Map 集合的遍历方法
     */

    public static void main(String [] LiuJinTao) {
        // 1、 通过键遍历 Map 集合
        Map<String, String> m = new HashMap<>();
        m.put("张三", "23");
        m.put("李四", "24");
        m.put("王五", "25");
        m.put("赵六", "26");
        Set<String> key = m.keySet();

        // 使用增强 for 遍历集合
        for (String s : key) {
            String valueResult = m.get(s);
            System.out.println(s + " = " + valueResult);
        }

        System.out.println("---------------------------------------------");

        // 使用 Lambda 表达式遍历集合
        m.forEach((Key, Value) -> {
            System.out.println(Key + " = " + Value);
        });

        System.out.println("---------------------------------------------");

        // 使用 迭代器 遍历集合
        Set<Map.Entry<String, String>> entrySet = m.entrySet();
        Iterator<Map.Entry<String, String>> iterator = entrySet.iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, String> entry = iterator.next();
            String Key = entry.getKey();
            String Value = entry.getValue();
            System.out.println(Key + " = " + Value);
        }
    }

执行结果:

李四 = 24
张三 = 23
王五 = 25
赵六 = 26


李四 = 24
张三 = 23
王五 = 25
赵六 = 26


李四 = 24
张三 = 23
王五 = 25
赵六 = 26


>

四、 HashMap

在这里插入图片描述

4.1 HashMap 的特点

在这里插入图片描述

HashMap内部有一个动态扩容的数组,数组的每个元素既可以是一个Entry对象,也可以是一个链表的头结点。
当向HashMap中添加一个键值对时,会先通过调用键对象的hashCode()方法计算得到一个哈希码,然后通过某种算法(通常是将哈希码与数组长度进行按位运算)转换成数组的索引位置。
如果数组该位置为空,则直接新建一个Entry放入;如果不为空,则发生哈希冲突,此时HashMap会在该位置上的链表(或红黑树)中进一步处理。在Java 1.7中,采用的是链表形式解决冲突;在Java 1.8中,如果链表长度达到一定程度(默认是8),则会将链表转换为红黑树以优化查询效率。
在这里插入图片描述

在这里插入图片描述

4.2 HashMap 练习一

在这里插入图片描述

package com.liujintao.map.hashmaptest;

import com.liujintao.map.student.Student;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class HashMapTest1 {
    public static void main(String[] LiuJinTao) {
        /**
         * 需求: 创建一个 HashMap 集合,键是学生对象(Student), 值是籍贯(String)。
         * 存储三个键值对元素,并遍历
         * 需求: 同姓名,同年龄认为是同一个学生
         */


        /**
         * 注意点:
         *      - 如果 HashMap 的键位置为一个 自定义对象, 那么对象内部就得重写 hashcode 和 equals 方法
         */

        // 1. 创建一个 HashMap 对象
        Map<Student, String> hm = new HashMap<>();

        // 2. 创建三个学生对象
        Student student1 = new Student("zhangsan", 23);
        Student student2 = new Student("lisi", 24);
        Student student3 = new Student("wangwu", 25);
        Student student4 = new Student("wangwu", 25);

        // 3. 将数据添加到HashMap 集合中
        hm.put(student1, "北京");
        hm.put(student2, "上海");
        hm.put(student3, "广东");
        hm.put(student4, "深圳");

        // 遍历集合 → 方法一: 通过键进行遍历
        Set<Student> keys = hm.keySet();
        for (Student key : keys) {
            String value = hm.get(key);
            System.out.println(key + value);
            /**
             * - 输出结果为;
             * Student{name = wangwu, age = 25}深圳
             * Student{name = lisi, age = 24}上海
             * Student{name = zhangsan, age = 23}北京
             */
        }
        System.out.println("------------------------------");

        // 遍历集合 → 方法二: 通过键值对方法进行遍历
        Set<Map.Entry<Student, String>> entries = hm.entrySet();
        for (Map.Entry<Student, String> entry : entries) {
            Student entryKey = entry.getKey();
            String entryValue = entry.getValue();
            System.out.println(entryKey + " + " + entryValue);
            /**
             * Student{name = wangwu, age = 25} + 深圳
             * Student{name = lisi, age = 24} + 上海
             * Student{name = zhangsan, age = 23} + 北京
             */
        }

        System.out.println("------------------------------");


        // 遍历集合 → 方法三: 通过匿名内部类方法(Lambda)
        hm.forEach((key, value) -> {
            System.out.println(key + " + " + value);
        });
        /**
         * Student{name = wangwu, age = 25} + 深圳
         * Student{name = lisi, age = 24} + 上海
         * Student{name = zhangsan, age = 23} + 北京
         */
    }
}

4.3 HashMap练习二

在这里插入图片描述

package com.liujintao.map.hashmaptest;

import java.util.*;

public class HashMapTest2 {
    /**
     * 需求: 某个班级80 名学生,现在需要组成秋游活动,班长提供了四个景点一次是(A,B,C,D)
     * 每个学生只能选择一个景点。统计出最终哪个景点想去的人数最多
     */
    public static void main(String [] LiuJinTao) {

        // 1. 创建景点
        String [] arr = {"A", "B", "C", "D"};
        for (String item : arr) {
            System.out.println(item);
        }


        // 2,景区选择生成
        HashMap<String, Integer> hm = getRandomSelect(arr);

        System.out.println(hm);

        // 3. 景区最大次数统计处理
        int max = 0;
        Set<Map.Entry<String, Integer>> entries = hm.entrySet();
        for (Map.Entry<String, Integer> entry : entries) {
            if (entry.getValue() > max) {
                max = entry.getValue();
            } //
        }

        for (Map.Entry<String, Integer> name : entries) {
            if (name.getValue() == max) {
                System.out.println(name.getKey() + " = " + max);
            }
        }
    }

    private static HashMap<String, Integer> getRandomSelect(String[] arr) {
        Random r = new Random();
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < 80; i++) {
            int number = r.nextInt(arr.length);
            list.add(arr[number]);
        }


        HashMap<String, Integer> hm = new HashMap<>();
        for (String name : list) {
            if (hm.containsKey(name)) {
                // 存在
                Integer count = hm.get(name);
                count++;
                hm.put(name, count);
            } else {
                // 不在
                hm.put(name, 1);
            }
        }

        return hm;
    }
}

五、linkedHashMap

在这里插入图片描述

package com.liujintao.map.hashmaptest;

import java.util.LinkedHashMap;

public class LinKedHashMapDemo {
    public static void main(String [] LiuJinTao) {
        // 1. 创建集合
        LinkedHashMap<String, Integer> lhm = new LinkedHashMap<>();

        // 2. 添加元素
        lhm.put("aaa", 111);
        lhm.put("bbb", 222);
        lhm.put("ccc", 333);
        lhm.put("ccc", 444);

        // 打印集合
        System.out.println(lhm);
        /**
         * 输出结果:{aaa=111, bbb=222, ccc=444}   有序、不重复
         */
    }
}

六、TreeMap

在这里插入图片描述

6.1 TreeMap练习一

在这里插入图片描述

package com.liujintao.map.map;

import java.util.Comparator;
import java.util.TreeMap;

public class TreeMapTest1 {
    public static void main(String[] LiuJinTao) {
        /*
            需求: 按照商品的 id 进行排序
         */

        // 1. 创建集合
        TreeMap<Integer, String> tm = new TreeMap<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });
        // 2. 添加元素
        tm.put(1, "香蕉");
        tm.put(2, "苹果");
        tm.put(3, "火龙果");
        tm.put(4, "芒果");
        tm.put(5, "梨");
        tm.put(6, "西瓜");

        // 1. System.out.println(tm); // 默认;升序 {1=香蕉, 2=苹果, 3=火龙果, 4=芒果, 5=梨, 6=西瓜}

        System.out.println(tm);  // 传递对象指定排序规则: {6=西瓜, 5=梨, 4=芒果, 3=火龙果, 2=苹果, 1=香蕉}
    }
}

6.1 TreeMap练习二

在这里插入图片描述

package com.liujintao.map.student;


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 : 表示已经在红黑树里面存在的元素

        // 返回值: 1. 负数(添加的元素比 o 小,存左边)   2. 正数(添加的元素比 o 大,存有边) 3. 0 (和 o 一样大 舍去)
        int i = this.getAge() - o.getAge();
        i = i == 0 ? this.getName().compareTo(o.getName()) : i;
        return i;
    }
}

package com.liujintao.map.map;

import com.liujintao.map.student.Student;

import java.util.TreeMap;

public class TreeMapTest2 {
    public static void main(String[] LiuJinTao) {
        // TreeMap 值存储自定义对象

        // 1. 创建集合
        TreeMap<Student, String> tm = new TreeMap<>();

        // 2. 创建学生对象
        Student student1 = new Student("张三", 23);
        Student student2 = new Student("李四", 24);
        Student student3 = new Student("王五", 25);

        tm.put(student1, "北京");
        tm.put(student2, "江苏");
        tm.put(student3, "江西");

        System.out.println(tm);
    }
}

// 运行结果:{Student{name = 张三, age = 23}=北京, Student{name = 李四, age = 24}=江苏, Student{name = 王五, age = 25}=江西}


6.3 TreeMap练习三

在这里插入图片描述

在这里插入图片描述

package com.liujintao.map.map;

import java.util.StringJoiner;
import java.util.TreeMap;

public class HashMapTest3 {
    public static void main(String [] LiuJinTao) {
        // 1. 创建字符集
        String string = "aaaaabbbbcccddeqqqqqqq";

        // 2. 创建结合,然后进行计数
        TreeMap<Character, Integer> tm = new TreeMap<>();

        // 3. 遍历字符串
        for (int i = 0; i < string.length(); i++) {
            // 将字符串遍历成字符集,然后进行比较添加规则
            char ch = string.charAt(i);
            // 3.1 如果存在,将值原有的基础上 +1 然后存到集合中
            if (tm.containsKey(ch)) {
                // 获取该字符的次数
                int count = tm.get(ch);
                count++;
                tm.put(ch, count);
            } else {
                // 3.2 如果不存在,则直接添加一次
                tm.put(ch, 1);
            }
        }

        // 4. 遍历,将集合格式化输出


        // 方式一: StringBuilder
        StringBuilder sb = new StringBuilder();
        tm.forEach((key, value) -> sb.append(key).append("(").append(value).append(")"));
        System.out.println(sb);

        // 方式二:StringJoiner
        StringJoiner sj = new StringJoiner("", "", "");
        tm.forEach((key, value) -> sj.add(key + "").add("(").add(value + "").add(")"));
        System.out.println(sj);

    }
}

4. TreeMap 总结

在这里插入图片描述

七、Map接口 集合的底层原理

八、可变参数

1. 可变参数的使用:
package com.liujintao.args;
public class ArgsDemo1 {
    public static void main(String[] LiuJinTao) {
        int resultSum = getSum(1, 2, 3, 4, 5, 6 , 7, 8, 9, 10 );
        System.out.println(resultSum);
    }

    public static int getSum (int...args) {
        int sum = 0;
        for (int item : args) {
            sum += item;
        }
        return sum;
    }
}
2. 可变参数的注意事项

在使用可变参数时,有一些注意事项:

  1. 可变参数必须是方法的最后一个参数:在方法声明中,如果有多个参数,可变参数必须是最后一个。这是因为可变参数会吞噬掉传递给方法的所有参数,所以Java需要确保它是最后一个参数,以便能够正确地解析方法调用。
  2. 使用时要注意空指针异常:在方法内部,可变参数被当作数组处理。因此,如果传递null作为可变参数,你需要在方法内部处理它,以避免空指针异常。
  3. 与普通数组的区别:虽然可变参数看起来像一个数组,但在底层它实际上是一个数组。这意味着你不能将另一个方法接受数组的方法直接传递给接受可变参数的方法,因为它们是不同类型的参数。

不要过度使用:虽然可变参数非常方便,但过度使用它们可能会使代码更难理解。在某些情况下,明确地声明参数可能更有意义。

3. 小结

在这里插入图片描述

九、Collections集合工具类

1. Collections是什么

在Java中,Collections是一个接口,位于java.util包下,用于表示一种数据结构的集合。它提供了一系列操作集合的方法,如添加、删除、搜索等,以及对集合进行排序和遍历的方法。

Collections接口的常用实现类包括:
List: 有序集合,可以包含重复元素。常见的实现类有ArrayList、LinkedList等。
Set: 不允许包含重复元素的集合。常见的实现类有HashSet、LinkedHashSet、TreeSet等。
Map: 键值对的集合,每个键唯一对应一个值。常见的实现类有HashMap、LinkedHashMap、TreeMap等。

2. Collections 常用方法

在这里插入图片描述

3. 基本使用示例:
package com.liujintao.collections;

import java.util.ArrayList;
import java.util.Collections;

public class CollectionsDemo1 {
    public static void main(String[] LiuJinTao) {
        /*
            collections集合工具类的基本使用
         */

        // 1. 创建 集合
        ArrayList<String> list = new ArrayList<>();

        // 2. 批量添加元素
        Collections.addAll(list, "qwer", "adsf", "likjd", "wer", "asdfa");

        // 3. 打印集合
        System.out.println(list);  // [qwer, adsf, likjd, wer, asdfa]


        // 4. 打乱集合
        Collections.shuffle(list);
        System.out.println(list); // [likjd, wer, adsf, qwer, asdfa]


    }
}

集合综合练习

1. 随机点名(一)

需求: 随机抽取姓名

public class ListRandomTest01 {
    public static void main(String[] LiuJinTao) {
        // 1. 创建集合
        ArrayList<String> list = new ArrayList<>();
        // 2. 批量添加元素
        Collections.addAll(list, "张三", "李四", "王五", "赵六", "钱七", "周八", "吴九", "郑十", "孙十一", "朱十二");

        // 3. 随机抽取名字
        // 方法一:
        Random r = new Random();
        int index = r.nextInt(list.size()); // 0 - 9
        System.out.println(list.get(index));


        // 方法二:
        Collections.shuffle(list);
        System.out.println(list.get(0));
    }
2. 随机点名(概率)

在这里插入图片描述

代码示例:
package com.liujintao.listtest;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

public class ListRandomTest02 {
       public static void main(String[] LiuJinTao) {
           // 1. 创建集合
           ArrayList<Integer> list = new ArrayList<>();
           // 2. 添加元素
           Collections.addAll(list, 1,1,1,1,1,1,1,0,0,0);
           System.out.println(list);

           // 3. 打乱集合
           Collections.shuffle(list);
           System.out.println(list);

           // 4. 随机抽取元素
           Random r = new Random();
           System.out.println(list.get(r.nextInt(list.size())));
           int index = list.get(r.nextInt(list.size()));


           System.out.println("------------换上数据进行完善代码------------------");

           // 1. 创建两个分类的集合
           ArrayList<String> boyList = new ArrayList<>();
           ArrayList<String> girlList = new ArrayList<>();
           // 2. 分别添加元素
           Collections.addAll(boyList, "张三", "李四", "王五", "赵六", "钱七", "周八", "吴九");
           Collections.addAll(girlList, "小美", "小丽", "小红");

           // 3. 分别打乱两个集合
           Collections.shuffle(boyList);
           Collections.shuffle(girlList);

           // 判断抽取,达到概率问题
           if (index == 1) {
               // 男生
               int boyIndex = r.nextInt(boyList.size());
               System.out.println(boyList.get(boyIndex));
           } else {
               // 女生
               int girlIndex = r.nextInt(girlList.size());
               System.out.println(girlList.get(girlIndex));
           }
    }
}

在这里插入图片描述

3. 随机点名(去重)

在这里插入图片描述

代码示例:
package com.liujintao.listtest;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

public class ListRandomTest03 {
    public static void main(String[] LiuJinTao) {
        ArrayList<String> list1 = new ArrayList<>();
        Collections.addAll(list1, "张三", "李四", "王五", "赵六", "钱七", "周八", "吴九", "郑十", "孙十一", "朱十二");
        ArrayList<String> list2 = new ArrayList<>();
        int count = list1.size();
        Random r = new Random();
        for (int i = 1; i <= 10; i++) {
            System.out.println("--------------------------------第" + i + "轮点名!----------------------------------");
            for (int j = 1; j <= count; j++) {
                int randomNumber = r.nextInt(list1.size());
                System.out.println(list1.get(randomNumber));
                String name = list1.remove(randomNumber);
                list2.add(name);
                System.out.println(list1);
            }
            // 给名单集合重新赋值
            list1.addAll(list2);
            // 清空临时集合
            list2.clear();
        }

    }
}

待补充。。。

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MakeFullStack

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值