Java集合类API详解
双列集合
双列集合的概念,也即一次添加一对数据的集合。双列集合的特点:
①双列集合一次需要存一对数据,分别为键和值
②键不能重复,值可以重复
③键和值是一一对应的,每一个键只能找到自己对应的值
④键+值这个整体我们称之为“键值对”或者“键值对对象”,在Java中叫做“Entry对象”
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() | 集合的长度,也就是集合中键值对的个数 |
V get(K key) | 通过key取出对应的值 |
put方法
方法put具有添加和覆盖的效果:在添加数据的时候,如果键不存在,那么直接把键值对对象添加到map集合当中;在添加数据的时候,如果键是存在的,那么会把原有的键值对对象覆盖,会把被覆盖的值进行返回。
remove方法
删除时会返回被删除的值。
Map的遍历方式
通过键找值
通过Map的keySet方法获取Map的所有键集合,然后对键进行遍历取出对应的值。
public static void main(String[] args) {
Map<String, String> alias = new HashMap<>();
alias.put("北京","京");
alias.put("山东","鲁");
alias.put("甘肃","陇");
alias.put("河北","冀");
// 1-1.添加成功,返回null
String returnVal = alias.put("上海","沪");
System.out.println(returnVal); // null
// 1-2.添加时覆盖,会返回被覆盖的值
String returnVal2 = alias.put("甘肃","甘");
System.out.println(returnVal2); // 陇
// 2.删除元素,通过key,方法返回被删除的值
String returnVal3 = alias.remove("上海");
System.out.println(returnVal3); // 沪
// 遍历
// 方法1.通过键取得值
// 1.取得键的集合
Set<String> keys = alias.keySet();
// 2.遍历key,并取出值
for (String key : keys) {
// 取出对应的值
String value = alias.get(key);
System.out.println(key + " = " + value);
}
System.out.println("===================");
// 方法2.通过迭代器
Iterator<String> iter = alias.keySet().iterator();
while (iter.hasNext()){
String key = iter.next();
String value = alias.get(key);
System.out.println(key + " = " + value);
}
System.out.println("=========3.1==========");
// 方法3.1.通过forEach匿名类或lambda
alias.keySet().forEach(new Consumer<String>() {
@Override
public void accept(String key) {
String value = alias.get(key);
System.out.println(key + " = " + value);
}
});
System.out.println("=========3.2==========");
// 方法3.2.通过forEach匿名类或lambda
alias.keySet().forEach((String key) -> System.out.println(key + " = " + alias.get(key)));
}
通过键值对遍历Entry
通过Map对象的entrySet()方法,取得条目集合Set。Entry接口是Map接口的内部接口。然后使用Entry对象的getKey()方法和getValue()取得键和值。
public static void main(String[] args) {
Map<String, String> alias = new HashMap<>();
alias.put("北京","京");
alias.put("山东","鲁");
alias.put("甘肃","陇");
alias.put("河北","冀");
// 1.取得Entry对象
Set<Map.Entry<String, String>> entries = alias.entrySet();
// 2.通过增强for遍历Entry对象
// 通过Entry的getKey和getValue方法得到键和值
for (Map.Entry<String, String> entry : entries) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
System.out.println("===3===");
// 3.通过迭代器的方法遍历
Iterator<Map.Entry<String, String>> iterator = entries.iterator();
while (iterator.hasNext()){
Map.Entry<String, String> entry = iterator.next();
System.out.println(entry.getKey() + " = " + entry.getValue());
}
System.out.println("===4===");
// 4.通过forEach方法(匿名类或lambda)
entries.forEach(new Consumer<Map.Entry<String, String>>() {
@Override
public void accept(Map.Entry<String, String> entry) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
});
System.out.println("===5===");
// 4.通过forEach方法(匿名类或lambda)
entries.forEach(entry -> System.out.println(entry.getKey() + " = " + entry.getValue()));
}
利用Lambda表达式遍历
方法名称 | 说明 |
deafult void forEach(BiConsumer<? super K, ? super V> action | 结合lambda遍历Map集合 |
HashMap类
HashMap的特点
1.HashMap底层是哈希表结构,其依赖hashCode方法和equals方法保证键的唯一(跟值无关)。如果键存储的是自定义对象,需要重写hashCode和equals方法,如果值存储自定义对象,不需要重写hashCode和equals方法
- HashMap是Map里面的一个实现类。
- 没有额外需要学习的特有方法,直接使用Map里面的方法就可以了。
- 特点都是由键决定的:无序、不重复、无索引
- HashMap跟HashSet底层原理是一模一样的,都是哈希表结构
- 链表长度超过8且数组长度>=64,底层存储结构自动转成红黑树
LinkedHashMap
●由键决定:有序、不重复、无索引。
●这里的有序指的是保证存储和取出的元素顺序一致
●原理:底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序。
TreeMap
●TreeMap跟TreeSet底层原理一样,都是红黑树结构的。
●由键决定特性:不重复、无索引、可排序
●可排序:对键进行排序。
●注意:默认按照键的从小到大进行排序,也可以自己规定键的排序规则
代码书写两种排序规则
●实现Comparable接口,指定比较规则。在JavaBean类中实现此接口。
●创建集合时传递Comparator比较器对象,指定比较规则。在创建集合作为参数传入,此比较器优先与Comparable接口。
练习:
需求1:
键:整数表示id
值:字符串表示商品名称
要求:按照id的升序排列、按照id的降序排列
需求2:
键:学生对象
值:籍贯
要求:按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名年龄视为同一个人。(姓名使用String类的compareTo方法进行比较)
需求一实现代码:
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
public class TreeMapDemo1 {
public static void main(String[] args) {
// 创建TreeMap
// 1.自定义按降序排列
Map<Integer, String> goods = new TreeMap<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
// 2.Integer Double等Java中已定义的类默认是
// 实现了Comparable接口,默认按升序排列
//Map<Integer, String> goods = new TreeMap<>();
goods.put(101, "iPhone");
goods.put(11, "Nexus");
goods.put(138, "Samsung");
System.out.println(goods);
}
}
需求二的Student类的compareTo方法实现代码:
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;
}
练习统计个数
需求:字符串“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 MapDemo1 {
public static void main(String[] args) {
// 字符串
String s ="aabgaiiiabcabcdgiabcdfe";
// 创建集合
TreeMap<Character, Integer> tm = new TreeMap<>();
// 遍历字符串s中的每一个字符,并统计出现的次数
for (int i = 0; i < s.length(); i++){
// 获取每一个字符
Character c = s.charAt(i);
if (tm.containsKey(c)){
// 如果字符已存在
Integer count = tm.get(c);
count++;
tm.put(c, count);
}else {
// 如果字符不在
tm.put(c, 1);
}
}
System.out.println(tm);
// 使用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);
// 使用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);
}
}
TreeMap小结
(1)TreeMap集合的特点是怎么样的?
●不重复、无索引、可排序(都是针对键,与值无关)
●底层基于红黑树实现排序,增删改查性能较好
(2)TreeMap集合排序的两种方式
●实现Comparable接口,指定比较规则
●创建集合时传递Comparator比较器对象,指定比较规则