一、前言
在Java中,Map是一个接口,用于存储键值对(key-value)的集合。Map中的每一个元素都是一个键值对,并且不允许有重复的键。键(key)是唯一的,并且与值(value)相关联。
实现类:Java标准库提供了几个实现Map接口的类,包括HashMap、LinkedHashMap、TreeMap、Hashtable、ConcurrentHashMap等。
- HashMap:基于哈希表的实现,通常用于快速查找和插入。
- LinkedHashMap:维护了插入顺序的HashMap。
- TreeMap:基于红黑二叉树的实现,自然排序或自定义排序。
- Hashtable:线程安全的HashMap,但性能较低。
- ConcurrentHashMap:线程安全的HashMap,支持高并发。
二、HashMap的基本语句
HashMap是Java集合框架中提供了一个实现Map接口的类。基于哈希表实现。
特点:键值对储存、哈希表结构、不保证顺序、允许使用null键和null值(null键只能有一个,因为键是唯一的)、初始容量(哈希表的大小)和加载因子(决定何时调整哈希表大小的参数)、非线程安全 、迭代功能、扩容机制。
性能:在理想情况下,HashMap的查找、插入和删除操作的平均时间复杂度都是O(1),但这是在哈希函数分布均匀且没有哈希冲突的情况下。如果哈希函数设计的不好,或者数据量非常大,哈希冲突或增多,性能收到影响。
1、创建HashMap
HashMap map=new HashMap();
2、添加值
map.put("CN","中国");
map.put(null,"空值");
map.put("NULL",null);
3、覆盖原来的value(键唯一)
map.put("CN","中国香港");
4、取值(只能通过key查找value)
System.out.println(map.get("CN"));
System.out.println(map.get(null));
System.out.println(map.get("NULL"));
5、元素个数
System.out.println(map.size());
6、清空元素
map.clear();
7、判断是否包含某个键
System.out.println(map.containsKey("CN"));
8、遍历
Set<Map.Entry<String,String>> entries=map.entrySet();
for (Map.Entry<String,String> entry:entries){
System.out.println("key:"+entry.getKey()+"value:"+entry.getValue());
}
9、获取value值
Collection<String> values=map.values();
10、for遍历
for (String value:values){
System.out.println(value);
}
11、遍历键
Set<String> keys=map.keySet();
for (String ky:keys){
System.out.println(map.get(ky));
}
12、forEach(lamada表达式:(形参)->{方法体})
map.forEach((key,value)->{
System.out.println("key:"+key+"value:"+value);
});
13、判断是否为空
System.out.println(map.isEmpty());
14、元素删除(元素删除后,根据key获得的是null)
map.remove("CN");
System.out.println(map.get("CN"));
15、元素替换
map.replace(null,"这是个新的值");
System.out.println(map.get(null));
1>练习 :
源码:
package day14;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Practice1 {
public static void main(String[] args) {
HashMap map=new HashMap();
map.put("Allen","JDBC");
map.put("Lucy","math");
map.replace("Lucy","CoreJava");
map.put("zhangsan","JSP");
map.put("ls","JSP");
// 遍历
Set<Map.Entry<String,String>> entries=map.entrySet();
for (Map.Entry<String,String> entry:entries){
System.out.println("key:"+entry.getKey()+" "+"value:"+entry.getValue());
}
System.out.println("-----------------------------------------------");
for (Map.Entry<String,String> entry:entries){
if (entry.getValue().equals("JSP")){
System.out.println(entry.getKey());
}
}
}
}
运行结果:
这里因为每个老师都是唯一的,但是可能会有很多个老师教同一个科目,根据键值对规则,老师->key,科目 ->value。
三、Hashtable的基本语句
Hashtable和HashMap的区别:
- HashMap的key和value允许为null,Hashtable的key和value不允许为null
- HashMap线程不安全,Hashtable线程安全
1、创建Hashtable集合对象
Hashtable table = new Hashtable();
2、集合添加值
table.put("CN","中国");
table.put("USA","美国");
table.put("US","英国");
3、元素个数
System.out.println(table.size());
4、清空集合
table.clear();
5、元素删除
table.remove("US");
6、元素替换
table.replace("USA","America");
7、遍历
(1)
Collection<String> values=table.values();
for (String value:values){
System.out.println(value);
}
(2)
Set<String> keys=table.keySet();
for (String ky:keys){
System.out.println(table.get(ky));
}
(3)
table.forEach((key,value)->{
System.out.println("key:"+key+"value:"+value);
});
(4)
Set<Map.Entry<String,String>> entries=table.entrySet();
for (Map.Entry<String,String> entry:entries){
System.out.println("key:"+entry.getKey()+"value:"+entry.getValue());
}
8、迭代枚举
// 把Map集合的value转化为枚举
Enumeration<String> ens=table.elements();
// 迭代枚举接口
while (ens.hasMoreElements()){
System.out.println(ens.nextElement());
}
Hashtable与HashMap的基本语句其实差不多,遍历方法有一点点出入
四、TreeMap基本语句
1、创建集合
TreeMap<String, Integer> map = new TreeMap();
2、添加值
map.put("b",2);
map.put("a",1);
map.put("d",4);
map.put("e",5);
map.put("c",3);
3、获取大于或等于key映射的实体对象
Map.Entry entry=map.ceilingEntry("d");//等于
System.out.println(entry.getKey()+"--"+entry.getValue());
4、严格大于
entry=map.higherEntry("d");
System.out.println(entry.getKey()+"--"+entry.getValue());
5、获取大于或等于key的键key
System.out.println(map.ceilingEntry("d"));
6、获取第一个实体对
entry=map.firstEntry();
System.out.println(entry.getKey()+"--"+entry.getValue());
7、获取第一个键
String key=map.firstKey();
System.out.println(key);
8、获取最后一个实体对
entry=map.lastEntry();
System.out.println(entry.getKey()+"--"+entry.getValue());
9、 获取最后一个key
System.out.println(map.lastKey());
10、截取map集合的一部分
SortedMap sm=map.subMap("b","d");
Set<Map.Entry> entries=sm.entrySet();
for (Map.Entry en:entries){
System.out.println("key"+en.getKey()+"--"+"value"+en.getValue());
}
11、获取小于或等于指定key的实体对象
entry=map.floorEntry("d");
System.out.println(entry.getKey()+"--"+entry.getValue());
12、严格小于
entry=map.lowerEntry("d");
System.out.println(entry.getKey()+"--"+entry.getValue());
13、获取小于或等于key的键
entry=map.floorEntry("d");
五、ConcurrentHashMap基本语句
1、创建集合对象
ConcurrentHashMap<Integer,Integer> con = new ConcurrentHashMap();
2、添加数据
con.put(1,3);
con.put(2,5);
con.put(3,7);
con.put(4,9);
con.put(6,7);
3、forEach遍历
// 获取一个检索时间
long before=System.currentTimeMillis();
con.forEach(5,(key,value)->{
System.out.println("key:"+key+",value:"+value);
});
long after=System.currentTimeMillis();
System.out.println("总消耗时间"+(after-before));
4、search搜索
String result=con.search(5,(key,value)->{
if (key==3){
return "存在3的key值";
}
return null;
});
System.out.println(result);
5、reduce
Integer val=con.reduce(5,(key,value)->{
return key+value;
},(o1,o2)->{
return o1*o2;
});
System.out.println(val);
六、Collections
1、创建集合
ArrayList<Integer> list = new ArrayList<>();
2、同时添加多个数据
Collections.addAll(list,1,2,3,34,5,6,7,8);
3、遍历
for (int i=0;i<list.size(); i++){
System.out.println(list.get(i));
}
4、集合中搜索数据(搜索方式:二分搜索)
int index=Collections.binarySearch(list,3);
System.out.println("位置:"+index);//没搜到,结果为负数
5、数据复制
List<Integer> newList=new ArrayList<>();
Collections.addAll(newList,0,0,0,0,0,0,0,0);
Collections.copy(newList,list);
6、数据填充(这里是将里面所有的数据都变成11)
Collections.fill(list,11);
7、最小值
Integer min=Collections.min(list);
System.out.println(min);
8、最大值
Integer max=Collections.max(list);
System.out.println(max);
9、集合数据翻转
Collections.reverse(list);
for (int i=0;i<list.size(); i++){
System.out.println(list.get(i));
}
10、将数据随机打乱
Collections.shuffle(list);
for (int i=0;i<list.size(); i++){
System.out.println(list.get(i));
}
11、交换
Collections.swap(list,2,3);//2,3为下标
将线程不安全的集合转化为线程安全的集合:关键字synchronizedList
七、案例练习
源码:
Employee:
package day15.practice1;
public class Employee {
private String name;
private String sal;
private MyDate birthday;
public Employee(String name,String sal,MyDate birthday){
this.name=name;
this.sal=sal;
this.birthday=birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSal() {
return sal;
}
public void setSal(String sal) {
this.sal = sal;
}
public MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", sal='" + sal + '\'' +
", birthday=" + birthday +
'}';
}
}
MyDate:
package day15.practice1;
public class MyDate {
private int year;
private int month;
private int day;
public MyDate(int year,int month,int day){
this.year=year;
this.month=month;
this.day=day;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
}
Test:
package day15.practice1;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Test {
public static void main(String[] args) {
Employee emp1=new Employee("zs","男",new MyDate(2000,2,17));
Employee emp2=new Employee("ls","男",new MyDate(2004,12,30));
Employee emp3=new Employee("zs","女",new MyDate(2002,8,17));
// 将这些对象放入ArrayList集合中
ArrayList<Employee> arrayList=new ArrayList<>();
arrayList.add(emp1);
arrayList.add(emp2);
arrayList.add(emp3);
Collections.sort(arrayList, new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
int s=0;
int s1=0;
int s2=0;
if (o1.getName().length()-o2.getName().length()==0){
for (int i=0;i<o1.getName().length();i++){
s=o1.getName().charAt(i)-o2.getName().charAt(i);
}
if (s!=0){
return s;
}
else {
s1=o1.getBirthday().getYear()-o2.getBirthday().getYear();
if (s1!=0){
return s1;
}
else {
s2=o1.getBirthday().getMonth()-o2.getBirthday().getMonth();
if (s2==0){
return o1.getBirthday().getDay()-o2.getBirthday().getDay();
}
else
return 0;
}
}
}
else
return 0;
}
});
for (Employee employee:arrayList){
System.out.println(employee);
}
}
}
运行结果:
八、小结
- List
-ArrayList : 数组 (动态数组),线程不安全
特点: 添加删除中间元素效率低,查询效率高。
-LinkedList: 双链表
特点: 添加元素效率高,查询效率低。
-Vector: 数组,线程安全
- Set
-HashSet: 哈希表(数组+链表+红黑二叉树)
-TreeSet:红黑二叉树
优点: 实现自然排序,查找效率稍高, 添加元素效率低。
- Map
1.HashMap:哈希表
方法:
void clear() :从这张地图中删除所有的映射。
boolean containsKey(Object key) :如果此映射包含指定键的映射,则返回 true 。
boolean containsValue(Object value) :如果此地图将一个或多个键映射到指定值,则返回 true 。
Set<Map.Entry<K,V>> entrySet() :返回此地图中包含的映射的Set视图。
void forEach(BiConsumer<? super K,? super V> action) :对此映射中的每个条目执行给定的操作,直到所有条目都被处理或操作引发异常。
V get(Object key) :返回到指定键所映射的值,或 null如果此映射包含该键的映射。
boolean isEmpty() :如果此地图不包含键值映射,则返回 true 。
Set<K> keySet() :返回此地图中包含的键的Set视图。
V put(K key, V value) :将指定的值与此映射中的指定键相关联。
V remove(Object key) :从该地图中删除指定键的映射(如果存在)。
boolean remove(Object key, Object value) :仅当指定的密钥当前映射到指定的值时删除该条目。
V replace(K key, V value) :只有当目标映射到某个值时,才能替换指定键的条目。
boolean replace(K key, V oldValue, V newValue) :仅当当前映射到指定的值时,才能替换指定键的条目。
int size() :返回此地图中键值映射的数量。
Collection<V> values() :返回此地图中包含的值的Collection视图。