一.LinkedHashMap集合:(是HashMap集合的儿子,Map集合的孙子)
1.特点:
2.代码实现:
1)键的唯一性:
package com.itheima.a01myMap;
import java.util.LinkedHashMap;
public class A07_LinkedHashMapDemo3 {public static void main(String[] args) {//1.创建集合LinkedHashMap<String,Integer> lhm=new LinkedHashMap<>();
//2.添加元素lhm.put("a",123);lhm.put("a",123);lhm.put("b",456);lhm.put("c",789);
//3.打印集合System.out.println(lhm);/* 运行结果为{a=123, b=456, c=789}添加了两个"a",123 ,但集合中只有一个"a",123 ,因为键是唯一的,不能重复,但值可以重复(和Map集合一样)*/}
}
2)键相同时,值不同->添加时以后来添加的为准:(添加元素的put方法有两个功能:添加,覆盖)
package com.itheima.a01myMap;
import java.util.LinkedHashMap;
public class A07_LinkedHashMapDemo3 {public static void main(String[] args) {//1.创建集合LinkedHashMap<String,Integer> lhm=new LinkedHashMap<>();
//2.添加元素lhm.put("a",123);lhm.put("a",111);lhm.put("b",456);lhm.put("c",789);
//3.打印集合System.out.println(lhm);/* 运行结果为{a=111, b=456, c=789}*/}
}
二.TreeMap集合:(Map集合的儿子)
1.特点与排序规则:
2.代码实现:(练习)
需求1:
键:整数表示id
值:字符串表示商品名称
要求:按照id的升序排列和按照id的降序排列
-
按照id的升序排列:id为整型,属于基本数据类型,默认升序排列,所以无需重写比较规则
package com.itheima.a02myTreeMap; import java.util.TreeMap; public class A01_TreeMapDemo1 {public static void main(String[] args) {//1.创建集合对象TreeMap<Integer,String> tm=new TreeMap<>(); //2.添加元素tm.put(1,"奥利奥");tm.put(5,"可口可乐");tm.put(2,"康师傅");tm.put(4,"雪碧");tm.put(3,"六个核桃"); //3.打印集合System.out.println(tm);//运行结果为{1=奥利奥, 2=康师傅, 3=六个核桃, 4=雪碧, 5=可口可乐}} }
Integer类里比较规则compare方法:
-
按照id的降序排列:id为整型,属于基本数据类型,默认升序排列,但此时要降序排列,
因此要重写比较规则-->要用到匿名内部类
package com.itheima.a02myTreeMap; import java.util.Comparator; import java.util.TreeMap; public class A01_TreeMapDemo1 {public static void main(String[] args) {//1.创建集合对象TreeMap<Integer,String> tm=new TreeMap<>(new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {//o1:当前要添加的元素//o2:表示已经在红黑树中存在的元素return o2-o1;/* 返回o1-o2为升序排列返回o2-o1为降序排列如果忘了,返回o1-o2和返回o2-o1挨个试就知道各自的排序规则了*/}}); //2.添加元素tm.put(1,"奥利奥");tm.put(5,"可口可乐");tm.put(2,"康师傅");tm.put(4,"雪碧");tm.put(3,"六个核桃"); //3.打印集合System.out.println(tm);//运行结果为{5=可口可乐, 4=雪碧, 3=六个核桃, 2=康师傅, 1=奥利奥}} }
需求2:
键:学生对象
值:籍贯
要求:按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名同年龄视为同一个人。
-
Student类:
package com.itheima.a02myTreeMap; 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 + "}";} @Overridepublic int compareTo(Student o) {/* this:表示当前要添加的元素形参o:表示已经在红黑树中存在的元素*//*返回值:this的减o的负数:表示当前要添加的元素是小的,存左边正数:表示当前要添加的元素是大的,存右边0:表示当前要添加的元素已经存在,则不存*/int i = this.getAge() - o.getAge();i = i==0?this.getName().compareTo(o.getName()):i;return i;}/* TreeMap集合底层是红黑树,书写比较再排序的规则无需重写hashCode和equals方法*/ }
-
测试类:
package com.itheima.a02myTreeMap; import java.util.TreeMap; public class A02_TreeMapDemo2 {public static void main(String[] args) {//1.创建集合TreeMap<Student,String> tm=new TreeMap<>();/* TreeMap集合在添加元素时是要对键进行比较再排序的,本例中键属于自定义对象,并没有指定比较再排序的规则,因此要在自定义对象类下指定比较再排序规则*/ //2.创建三个学生对象Student s1=new Student("zhangsan",24);Student s2=new Student("lisi",23);Student s3=new Student("wangwu",24); //3.添加元素tm.put(s1,"江苏");tm.put(s2,"天津");tm.put(s3,"北京"); //4.打印集合System.out.println(tm);/*运行结果为{Student{name = lisi, age = 23}=天津, Student{name = wangwu, age = 24}=北京,Student{name = zhangsan, age = 24}=江苏}*/} }
需求3:统计个数
需求:字符串"aababcabcdabcde"
请统计字符串中每一个字符出现的次数,并按照以下格式输出
输出结果:
a(5)b(4)c(3)d(2)e(1)
分析:本题有关统计:
1) 计数器思想-->不适用,因为计数器思想对于统计的数量比较多或者统计的数量未知是难以实现的
2)利用Map集合进行统计-->适用,HashMap集合和TreeMap集合,其中键表示要统计的内容,值表示次数
注:如果题目中没有要求对结果进行排序,默认使用HashMap集合,
如果题目中要求对结果进行排序,则使用TreeMap集合
本题结果是升序的(字母ASCII码升高的顺序)-->使用TreeMap集合
(用集合的小习惯:用到了再创建,用不到则不创建)
错解:
package a36practice;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.BiConsumer;
public class TreeMapDemo {public static void main(String[] args) {//1.创建集合TreeMap<Character,Integer> tm=new TreeMap<>();
//2.字符串String str="aababcabcdabcde";
//3.调用method方法method(str,tm);
//4.遍历集合tm.forEach(new BiConsumer<Character, Integer>() {@Overridepublic void accept(Character key, Integer value) {System.out.println(key+"("+value+")");}});}
//定义方法//需要字符,集合//返回集合private static TreeMap<Character,Integer> method(String str,TreeMap<Character,Integer> tm){//1.遍历集合的键看是否有字符cSet<Character> keys = tm.keySet();for (Character key : keys) {//2.遍历字符串,依次判断哪一个字符与外循环(遍历集合)的键匹配/* 一个键上就要把字符串的某一个字符全部统计完因此键在外循环,字符为内循环*/for (int i = 0; i < str.length(); i++) {//3 获取指定索引上的字符Character c=str.charAt(i);//4.键为key,进行判断if (tm.containsKey(c)) { //判断条件不是key==c,而是tm.containsKey(c)-->键上是否有c//代表已有,键不动,值加1即可Integer value = tm.get(key);value++;//集合添加-->别忘了这步tm.put(c, value);} else {//代表键不存在,给键赋c,值为1-->因为第一次出现tm.put(c, 1);/*key=c;Integer value = tm.get(key);value++; 这么写不对,value++就不对*/}}}return tm;}
}
错误原因:方法method里Set<Character> keys = tm.keySet();就有问题,因为第一次执行时集合tm长度为0,键为空,因此Set<Character>就为空,导致for (Character key : keys)循环不了。
正解:遍历方式有三种
第一种:利用StringBuilder类里的append方法实现拼接
package com.itheima.a02myTreeMap;
import java.util.TreeMap;
import java.util.function.BiConsumer;
public class A03_TreeMapDemo3 {public static void main(String[] args) {//1.定义字符串String s="aababcabcdabcde";
//2.创建集合TreeMap<Character,Integer> tm=new TreeMap<>();
//3.遍历字符串得到里面的每一个字符for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);/* 拿着c(c代表字符串里的某个字符)到集合中判断是否存在存在,表示当前字符又出现了一次不存在,表示当前字符是第一次出现*/if(tm.containsKey(c)){//存在//先把存在的这个字符已经出现的次数拿出来Integer count = tm.get(c);//这个代表把次数拿出来再赋值给count,第二次循环不会清除之前的数,更不会弄为0//当前字符又出现了一次,则自增count++;//把自增之后的结果再添加到集合当中tm.put(c,count);}else {//不存在/* 给键赋值。值为1,因为第一次出现再添加到集合中*/tm.put(c,1);}}
/* //4.打印集合System.out.println(tm);//运行结果为{a=5, b=4, c=3, d=2, e=1}上述打印方式不符合题目要求-->可通过遍历解决*/
//4.遍历集合,并按照指定的格式拼接即 a(5)b(4)c(3)d(2)e(1)StringBuilder sb=new StringBuilder();
tm.forEach(new BiConsumer<Character, Integer>() {@Overridepublic void accept(Character key, Integer value) {sb.append(key).append("(").append(value).append(")");}});
System.out.println(sb);}
}
第二种:利用StringJoiner类里的add方法实现拼接
package com.itheima.a02myTreeMap;import java.util.StringJoiner;
import java.util.TreeMap;
import java.util.function.BiConsumer;public class A03_TreeMapDemo3 {public static void main(String[] args) {//1.定义字符串String s="aababcabcdabcde";//2.创建集合TreeMap<Character,Integer> tm=new TreeMap<>();//3.遍历字符串得到里面的每一个字符for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);/* 拿着c(c代表字符串里的某个字符)到集合中判断是否存在存在,表示当前字符又出现了一次不存在,表示当前字符是第一次出现*/if(tm.containsKey(c)){//存在//先把存在的这个字符已经出现的次数拿出来Integer count = tm.get(c);//这个代表把次数拿出来再赋值给count,第二次循环不会清除之前的数,更不会弄为0//当前字符又出现了一次,则自增count++;//把自增之后的结果再添加到集合当中tm.put(c,count);}else {//不存在/* 给键赋值。值为1,因为第一次出现再添加到集合中*/tm.put(c,1);}}/* //4.打印集合System.out.println(tm);//运行结果为{a=5, b=4, c=3, d=2, e=1}上述打印方式不符合题目要求-->可通过遍历解决*///4.遍历集合,并按照指定的格式拼接即 a(5)b(4)c(3)d(2)e(1)StringJoiner sj=new StringJoiner("","","");/*创建StringJoiner对象时形参要指定开始标记,结束标记和间隔符号本例中开始标记,结束标记和间隔符号全用长度为0的字符串*/tm.forEach(new BiConsumer<Character, Integer>() {@Overridepublic void accept(Character key, Integer value) {sj.add(key+"").add("(").add(value+"").add(")");/* StringJoiner类里的add方法的参数必须是字符串,若不是字符串,则在后面加双引号即""即可*/}});System.out.println(sj);}
}
第三种:直接遍历输出
package com.itheima.a02myTreeMap;import java.util.TreeMap;public class A03_TreeMapDemo3 {public static void main(String[] args) {//1.定义字符串String s="aababcabcdabcde";//2.创建集合TreeMap<Character,Integer> tm=new TreeMap<>();//3.遍历字符串得到里面的每一个字符for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);/* 拿着c(c代表字符串里的某个字符)到集合中判断是否存在存在,表示当前字符又出现了一次不存在,表示当前字符是第一次出现*/if(tm.containsKey(c)){//存在//先把存在的这个字符已经出现的次数拿出来Integer count = tm.get(c);//这个代表把次数拿出来再赋值给count,第二次循环不会清除之前的数,更不会弄为0//当前字符又出现了一次,则自增count++;//把自增之后的结果再添加到集合当中tm.put(c,count);}else {//不存在/* 给键赋值。值为1,因为第一次出现再添加到集合中*/tm.put(c,1);}}/* //4.打印集合System.out.println(tm);//运行结果为{a=5, b=4, c=3, d=2, e=1}上述打印方式不符合题目要求-->可通过遍历解决*///4.遍历集合,并按照指定的格式拼接即 a(5)b(4)c(3)d(2)e(1)tm.forEach((key,value) -> System.out.print(key+"("+value+")"));}
}