Java集合—Map集合系列(从0到1 详解,附有代码+案例)

Java集合—双列集合系列

特点

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

在这里插入图片描述

在这里插入图片描述

18.12 Map系列集合

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()集合的长度,也就是集合中键值对的个数
import java.util.HashMap;
import java.util.Map;
public class Test {
    public static void main(String[] args) {
        //1.创建Map集合的对象
        Map<String,String> m = new HashMap<>();
        //2.添加元素
        m.put("兔子","胡萝卜");
        m.put("狗","骨头");
        m.put("羊","草");
        //put方法的细节:
        //添加/覆盖
        //在添加数据的时候,如果键不存在,那么直接把键值对对象添加到map集合当中,方法返回null
        //在添加数据的时候,如果键是存在的,那么会把原有的键值对对象覆盖,会把被覆盖的值进行返回。
        String value1 = m.put("青蛙", "虫子");//null
        System.out.println(value1);

        String value2 = m.put("狗", "肉");
        System.out.println(value2);//骨头
        System.out.println(m);
      //{青蛙=虫子, 兔子=胡萝卜, 狗=肉, 羊=草}

        //3.删除,根据键删除键值对元素
        String value3 = m.remove("狗");
        System.out.println(value3);//肉
        System.out.println(m);//{青蛙=虫子, 兔子=胡萝卜, 羊=草}

        // 4.移除所有的键值对元素
        //m.clear();
        //System.out.println(m);//{}

        // 5.判断集合是否包含指定的键
        boolean key1 = m.containsKey("青蛙");
        System.out.println(key1);//true

        // 6.判断集合是否包含指定的值
        boolean value4 = m.containsValue("虫子");
        System.out.println(value4);//true

        // 7.判断集合是否为空
        boolean isempty = m.isEmpty();
        System.out.println(isempty);//false

        // 8.集合的长度,也就是集合中键值对的个数
        int size = m.size();
        System.out.println(size);//3
    }
}

18.13 Map的三种遍历方式

18.13.1键找值

思路:

  • 首先,需要把键全部放在一个单例集合,用keySet()方法
  • 然后,遍历单列集合得到每一个键,再通过get()方法找到每个键对应的值
  • 输出
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;

public class Test {
    public static void main(String[] args) {
        //1.创建Map集合的对象
        Map<String,String> m = new HashMap<>();
        //2.添加元素
        m.put("兔子","胡萝卜");
        m.put("狗","骨头");
        m.put("羊","草");
        //3.通过键找值

        //3.1获取所有的键,把这些键放到一个单列集合当中
        Set<String> keys = m.keySet();

        //3.2增强for遍历装着键的单列集合,得到每一个键
        for (String key : keys) {
            //3.3 利用map集合中的键获取对应的值  get
            String s = m.get(key);
            System.out.println(key+"="+s);
        }
        
        // 迭代器遍历装着键的单列集合
        Iterator<String> it = keys.iterator();
        while (it.hasNext()){
            String key1 = it.next();
            // System.out.println(s);//获取键
            //键通过get 方法获取对应的值
            String value1 = m.get(key1);
            System.out.println(key1+"="+value1);
            //兔子=胡萝卜  狗=骨头  羊=草
        }
        
        //Lambda表达式遍历装着键的单列集合
        keys.forEach(new Consumer<String>() {
            @Override
            public void accept(String key2) {
                // System.out.println(key2);
                String value2 = m.get(key2);
                System.out.println(key2+"="+value2);
               //兔子=胡萝卜  狗=骨头  羊=草
            }
        });

    }
}

18.13.2 键值对

思路:

  • 通过entrySet()方法获取所有的键值对对象,放在Set集合中,集合名字为entries
  • 遍历entries这个集合,去得到里面的每一个键值对对象entry
  • 利用entry调用getKey()和getValue()方法获取键和值(或者直接输出entry)
  • 输出
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;

public class Test02 {
    public static void main(String[] args) {
        // Map的第2种遍历方式:键值对,

        //1.创建Map集合的对象
        Map<String,String> map =new HashMap<>();
        //2.添加元素
        map.put("兔子","胡萝卜");
        map.put("狗","骨头");
        map.put("羊","草");

        // 3.遍历,通过键值对对象进行遍历
        //通过一个方法获取所有的键值对对象,返回一个Set集合
        Set<Map.Entry<String, String>> entries = map.entrySet();

//3.1 增强for遍历装着键值对的单列集合entries,去得到里面的每一个键值对对象
        for (Map.Entry<String, String> entry : entries) {
            // System.out.println(entry);
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key+"="+value);
        }

// 3.2迭代器遍历装着键值对的单列集合
Iterator<Map.Entry<String, String>> it = entries.iterator();
        while (it.hasNext()){
            Map.Entry<String, String> next = it.next();
            // System.out.println(next);
            String key = next.getKey();
            String value = next.getValue();
            System.out.println(key+"="+value);
        }
//3.3Lambda表达式遍历装着键值对的单列集合
 entries.forEach(new Consumer<Map.Entry<String, String>>() {
            @Override
           public void accept(Map.Entry<String, String> s) {
                // System.out.println(s);
                String key = s.getKey();
                String value = s.getValue();
                System.out.println(key+"="+value);
            }
        });
        
    }
}

18.13.3 Lambda表达式

import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;

public class Test03 {
    public static void main(String[] args) {
        // Map的第三种遍历方式

        // 创建集合的对象
        Map<String,String> map = new HashMap<>();
        // 添加元素
        map.put("兔子","胡萝卜");
        map.put("狗","骨头");
        map.put("羊","草");
				//内名内部类形式
        map.forEach(new BiConsumer<String, String>() {
            @Override
            public void accept(String key, String value) {
                System.out.println(key+"=>"+value);
            }
        });
        // Lambda表达式遍历
      	//底层:
        //forEach其实就是利用第二种方式进行遍历,依次得到每一个键和值
        //再调用accept方法
        map.forEach((String key, String value)-> {
                System.out.println(key+"=>"+value);
            }
        );

    }
}

18.14 HashMap

18.14.1 介绍

  • 特点都是由键决定的:无序、不重复、无索引

  • HashMap是Map里面的一个实现类

  • 没有额外的特有方法,直接使用Map里的方法就可以

  • HashMap跟HashSet底层原理一样,都是哈希表

  • 依赖hashCode和equals方法保证键的唯一

  • 如果键存储的是自定义对象,需要重写hashCode方法和equals方法

  • 如果键存储自定义对象,不需要重写hashCode和equals方法

在存数据时,是利用键计算哈希值,跟值无关,如果要插入的位置有元素,put()方法则会覆盖原有的元素。

18.14.2 Test

test01 存储自定义对象

需求:创建一个HashMap集合,键是学生对象(Student),值是籍贯(String)。
存储三个键值对元素,并遍历
要求:同姓名,同年龄认为是同一个学生

public class Student {
    private String name;
    private int age;

    public Student() {}
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() { return name;}
    public void setName(String name) {this.name = name;}
    public int getAge() {  return age;}
    public void setAge(int age) {this.age = age;}

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
public class StudentTest {
    public static void main(String[] args) {
        /*
需求:创建一个HashMap集合,键是学生对象(Student),值是籍贯(String)。
存储三个键值对元素,并遍历
要求:同姓名,同年龄认为是同一个学生
         */
        // 创建学生对象
        Student s1 = new Student("zhangsan",23);
        Student s2 = new Student("lisi",24);
        Student s3 = new Student("wangwu",25);
        Student s4 = new Student("wangwu",25);

        //1.创建HashMap的对象
        HashMap<Student,String> hm = new HashMap<>();
        hm.put(s1,"A省");
        hm.put(s2,"B省");
        hm.put(s3,"c省");
        hm.put(s4,"D省");//会覆盖s1

        // 1.键找值
        // 把所有的键放在一个单列集合
        Set<Student> keys  = hm.keySet();
        for (Student stuKey : keys) {
            String stuValue = hm.get(stuKey);
            System.out.println(stuKey+"=>"+stuValue);
        }

        //2. 键值对
  Set<Map.Entry<Student, String>> entries = hm.entrySet();
  for (Map.Entry<Student, String> entry : entries) {
            Student key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key+"=>"+value);
        }
      
       //3. Lambda表达式
        hm.forEach(new BiConsumer<Student, String>() {
            @Override
            public void accept(Student student, String s) {
                System.out.println(student+"=>"+s);
            }
        });

    }
}
test02 利用HashMap统计

18.15 LinkedHashMap

(可直接使用Map里面的方法)

  • 决定:有序、不重复、无索引
  • 有序指:存储和取出元素的顺序是一致的。

原理

底层数据结构依然是哈希表,只是每个键值对元素又额外多了一个双链表的机制记录存储顺序,保证存和取的顺序一样。

在这里插入图片描述

import java.util.LinkedHashMap;

public class Test {
    public static void main(String[] args) {
 // 创建集合
  LinkedHashMap<String,Integer> lhp = new LinkedHashMap<>();
        // 添加元素
        lhp.put("a",123);
        lhp.put("a",666);
        lhp.put("b",456);
        lhp.put("c",789);
        // 打印元素
        System.out.println(lhp);//{a=666, b=456, c=789}
    }
}

18.16 TreeMap

18.16.0概述

  • TreeMao跟TreeSet底层原理一样,都是红黑树结构,增删改查性能较好。
  • 由键决定特定:不重复、无索引、可排序
  • 可排序:对键进行排序
  • 注意:默认按照键的从小到大进行排序的,也可以自己规定键的排序规则。

18.16.1排序规则

  • 实现Comparable接口,指定比较规则

  • 创建集合时传递Comparator比较器对象,指定比较规则

    新的统计思想:利用map集合进行统计
    如果题目中没有要求对结果进行排序,默认使用HashMap
    如果题目中要求对结果进行排序,请使用TreeMap
      
    键:表示要统计的内容
    值:表示次数
    

18.16.2案例

test01 排序

TreeMap集合:基本应用
需求1:
键:整数表示id
值:字符串表示商品名称
要求1:按照id的升序排列
要求2:按照id的降序排列

import java.util.TreeMap;

public class Test {
    public static void main(String[] args) {

        // 创建集合对象
       //Integer Double 默认情况下都是按照升序排列的
       //String 按照字母再ASCII码表中对应的数字升序进行排列
        TreeMap<Integer,String>  hm =new TreeMap<>();
        // 添加元素
        hm.put(5,"可乐");
        hm.put(2,"雪碧");
        hm.put(1,"酸梅汤");
        hm.put(6,"哇哈哈");
      //默认按照键的从小到大进行排序的
        System.out.println(hm);
        //{1=酸梅汤, 2=雪碧, 5=可乐, 6=哇哈哈}
    }
}

自己指定规则排序

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

public class Test02 {
    public static void main(String[] args) {
        // 创建集合对象
        TreeMap<Integer,String> hm =new TreeMap<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                //o1:当前要添加的元素
                //o2:表示已经在红黑树中存在的元素
                return o2-o1;
            }
        });
        // 添加元素
        hm.put(5,"可乐");
        hm.put(2,"雪碧");
        hm.put(1,"酸梅汤");
        hm.put(6,"哇哈哈");
        System.out.println(hm);
        //{6=哇哈哈, 5=可乐, 2=雪碧, 1=酸梅汤}
    }
}
test02 键的位置是自定义对象

TreeMap集合:基本应用
需求2:
键:学生对象 值:籍贯
要求:按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名 年龄视为同一个人。

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Student o) {
        //this:表示当前要添加的元素
        //o:表示已经在红黑树中存在的元素

        //返回值:
        //负数:表示当前要添加的元素是小的,存左边
        //正数:表示当前要添加的元素是大的,存右边
        //0:表示当前要添加的元素已经存在,舍弃

        int i = this.getAge() - o.age;
     //compareTo()方法,默认按照字符在ASCll码表中的数字升序进行排序
     int i1 = i == 0 ? this.getName().compareTo(o.name) : i;
     return i1;
    }
}
import java.util.TreeMap;

public class StudentTest {
    public static void main(String[] args) {
        // 创建集合对象
        TreeMap<Student ,String> hm = new TreeMap<>();
        // 创建学生对象
        Student s1 = new Student("zhangsan",23);
        Student s2 = new Student("lisi",24);
        Student s3 = new Student("wangwu",25);
        Student s4 = new Student("ahaoliu",23);
         // 添加元素给集合
        hm.put(s1,"河南");
        hm.put(s2,"山东");
        hm.put(s3,"南京");
        hm.put(s4,"上海");
        //System.out.println(hm);
        Set<Student> keys  = hm.keySet();
        for (Student key : keys) {
            String value = hm.get(key);
            System.out.println(key+"=>"+value);
          //Student{name='ahaoliu', age=23}=>上海
          //Student{name='zhangsan', age=23}=>河南
         //Student{name='lisi', age=24}=>山东
         //Student{name='wangwu', age=25}=>南京
        }
    }
}
test03 TreeMap统计

需求:
字符串“aababcabcdabcde”
请统计字符串中每一个字符出现的次数,并按照以下格式输出
输出结果:
a(5)b(4)c(3)d(2)e(1)

import java.util.StringJoiner;
import java.util.TreeMap;
import java.util.function.BiConsumer;

public class Test {
    public static void main(String[] args) {

        String s = "aababcabcdabcde";
        // 创建集合对象
        TreeMap<Character,Integer> tm = new TreeMap<>();
        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);
            }
        }
        // 打印
        System.out.println(tm);//{a=5, b=4, c=3, d=2, e=1}

   // StringBuilder拼接
   StringBuilder sb = new StringBuilder();
   tm.forEach(new BiConsumer<Character, Integer>() {
       @Override
       public void accept(Character key, Integer value) {
       sb.append(key).append("(").append(value).append(")");
            }
        });
        System.out.println(sb);//a(5)b(4)c(3)d(2)e(1)
        System.out.println();

  // StringJoiner拼接
  StringJoiner sj = new StringJoiner("","","");
  tm.forEach(new BiConsumer<Character, Integer>() {
      @Override
      public void accept(Character key, Integer value) {
     sj.add(key+"").add("(").add(value+"").add(")");
            }
        });
        System.out.println(sj);//a(5)b(4)c(3)d(2)e(1)

    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

蔚一

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

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

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

打赏作者

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

抵扣说明:

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

余额充值