day06-Lambda+Map+HashMap
学习任务
1 掌握Lambda表达式的语法
2 掌握Map的基本操作
3 记住HashMap工作原理
4 了解HashTable特点
Lambda表
文章目录
- day06-Lambda+Map+HashMap
- Lambda表
- 达式
- Map集合
- HashMap工作原理
- HashTable
- 练习
- 1 定义Map保存 向集合中添加一组数据 查看体育老师是谁 查看是否开设 劳动课 修改英语老师为 刘老师 查看总共开设了多少课程 查看都有哪些老师有教学任务
- 2 定义Map保存 向集合中添加一组数据<课程名称,老师姓名> 查看3号 删除4号 修改5号 删除所有不及格同学
- 3 定义Map保存模拟用户注册与登录,程序运行界面------------------------欢迎来到动力商城------------------------------ 1 注册 2 登录 3 退出 请输入你的操作: 1===================注册====================== 请输入用户名: lisi 该用户名已存在,请重新输入:wangwu 请输入密码: 123 注册成功------------------------欢迎来到动力商城------------------------------ 1 注册 2 登录 3 退出请输入你的操作: 2===================登录====================== 请输入用户名: lisi 请输入密码: 123 用户名或密码不正确,
- 4 有字符串:adfkjalkjfglakjglkajsdflkjadslkfjadslkjflakdsjflkadsjlfkjaslkfjdalkjgflkagjlfhjglkafdhlkjadslkadjsfsfjkladsfja统计字符串中每个字符出现的次数, 把保存到Map集合中
达式
Lambda表达式是在JDK8中 新增的重磅更新
当接口只需要重写一个抽象方法时,可以使用Lambda表达式即把接口抽象方法的参数列表 与 方法体使用箭头->连接,就是Lambda表达式可以把Lambda看作是一个匿名方法
lambda语法:( 参数列表 ) -> { Lambda体 }说明:1) 参数列表中参数类型可以省略2) 如果只有一个参数时, 小括弧可以省略3) 如果Lambda体只有一条语句则大括弧可以省略 如果这条语句是return语句则return关键字也需要省略4) Lambda表达式并 没有提高执行效率, 仅仅是使代码更简洁,更优雅
List<String> list = new ArrayList<>();
list.add("hello");
list.add("world");
list.add("good");
list.add("nice");
list.add("boy");
list.add("girl");
list.add("feifei");
System.out.println(list); //[hello, world, good, nice, boy, girl, feifei]
调用list集合的sort(Comparator)方法可以实现排序,形参Comparator接口可以传递匿名内部类对象
list.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
1 Comparator接口只需要重写一个抽象方法, 可以使用Lambda表达式, 可以简单的把Lambda表达式看作是一个匿名方法, 即使用箭头->把抽象方法的参数列表与方法体连接起来即可
list.sort((String o1, String o2) -> {
return o1.compareTo(o2);
});
参数列表中参数类型可以省略
list.sort(( o1, o2) -> {
return o1.compareTo(o2);
});
Lambda体只有一条语句时,大括弧可以省略, 如果这条语句是return语句则return关键字也需要省略
list.sort((o1, o2) -> o1.compareTo(o2));
System.out.println(list); //[boy, feifei, girl, good, hello, nice, world]
2 Collection集合有forEach(Consumer<? super T> action) 方法可以遍历集合中的每个元素
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
//系统会把前面集合的每个 元素传递给accept方法的参数
System.out.println(s);
}
});
Consumer接口只需要重写一个抽象方法, 可以使用Lambda表达式
list.forEach(s -> System.out.println(s));
3 Collection集合的removeIf(Predicate<? super E> filter) 删除符合条件的若干元素
list.removeIf(new Predicate<String>() {
@Override
public boolean test(String s) {
//系统会把前面集合的每个 元素传递给形参, 在方法体中返回布尔表达式
return s.length() >= 5;
}
});
Predicate接口只需要重写一个抽象方法, 可以使用Lambda表达式
list.removeIf(s -> s.length() >= 5);
System.out.println(list); //[boy, girl, good, nice]
4 当Lambda体就是一个方法调用时,可以使用方法引用 的形式, 格式类: 类名|对象名::方法名
list.forEach(System.out::println); //调用System.out对象的println方法
list.sort(String::compareTo); //调用String类中定义的compareTo方法
Map集合
集合是用于存储引用数据的容器Map集合是按对的形式存储数据
Map的基本操作
//1 创建Map集合存储<学生姓名,成绩>, 通过泛型指定键值数据类型, Map接口赋值实现类对象
Map<String, Integer> map = new HashMap<>();
//2 调用 put( k , v) 向集合中添加一对数据
map.put("zhangsan", 80);
map.put("lisi", 70);
map.put("wangwu", 80);
map.put("zhaoliu", 90);
map.put("chenqi", 100);
//3 直接打印map时, 会调用map引用 的hashMap对象的toString()
Map集合中键值对实际存储的顺序与添加顺序可能不一样. 当前HashMap集合存储的位置跟键的哈希码有关
System.out.println(map); //{lisi=70, zhaoliu=90, zhangsan=80, wangwu=80, chenqi=100}
//4 Map集合中的键不允许重复的, 在put添加键值对时,如果键已存在则使用新的value值替换原来的value值,并返回 旧的value值
Integer old = map.put("lisi", 66);
System.out.println( old ); //70
System.out.println( map );//{lisi=66, zhaoliu=90, zhangsan=80, wangwu=80, chenqi=100}
在put(k,v)添加键值对时,如果k键不存在,即这是第一次添加,put方法返回null
old = map.put("hanyi", 100);
System.out.println( old ); //null
System.out.println( map );//{lisi=66, hanyi=100, zhaoliu=90, zhangsan=80, wangwu=80, chenqi=100}
//5 判断
调用get(k)返回map集合中k键的value值
System.out.println( map.get("zhaoliu")); //查看map集合中zhaoliu的成绩: 90
System.out.println( map.get("liuer")); //null, 键不存在get()返回null
调用containsKey(k)判断map集合中的第一列是否包含k
System.out.println( map.containsKey("lisi")); //true表示map集合中存在姓名为lisi的同学
System.out.println( map.containsKey("lisisi")); //false表示map集合中不存在姓名为lisisi的同学
调用containsValue( v) 判断map集合中第二列是否包含v
System.out.println( map.containsValue(100)); //true, 表示map集合中存在成绩为100分的同学
System.out.println( map.containsValue(10)); //false, 表示map集合中不存在成绩为10分的同学
System.out.println( map.size() ); //6, map中存在6个键值对
System.out.println( map.isEmpty()); //false
//6 调用keySet()返回map中第一列所有 键的集合. map的键不允许重复所以方法返回值是Set集合
Set<String> keySet = map.keySet();
System.out.println( keySet ); //[lisi, hanyi, zhaoliu, zhangsan, wangwu, chenqi]
调用values()返回map中第二列所有 值的集合, value值是可以重复的所以返回值是Collection集合
Collection<Integer> values = map.values();
System.out.println(values); //[66, 100, 90, 80, 80, 100]
调用entrySet()返回所有Entry的集合, Entry就是一个键值对,它的数据类型是 Map.Entry, 表示Entry是Map接口中的一个内部接口. 将来看到 类名1.类名2 形式时,表示类名2是类名1 的内部类
Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
System.out.println(entrySet);
//[lisi=66, hanyi=100, zhaoliu=90, zhangsan=80, wangwu=80, chenqi=100]
//7 replace(k , v)把map集合中k键的值替换为v, 并返回旧的value值
old = map.replace("hanyi", 99); //把map集合中hanyi的成绩修改为99
System.out.println( old ); //100
System.out.println(map);
//{lisi=66, hanyi=99, zhaoliu=90, zhangsan=80, wangwu=80, chenqi=100}
put(k,v)的本职工作是向集合中添加(k,v)键值对, 当k键已存在时,功能就是替换; replace(k,v)本职工作是替换,前提是k键已存在, 如果k键不存在没有添加的功能
//8 remove(k )删除map集合中k键对应的键值对, 返回删除键值中的value值
old = map.remove("chenqi");
System.out.println( old ); //100
System.out.println(map);
//{lisi=66, hanyi=99, zhaoliu=90, zhangsan=80, wangwu=80}
//9 调用forEach(BiConsumer)可以遍历Map的每个Entry
/* map.forEach(new BiConsumer<String, Integer>() {
@Override
public void accept(String s, Integer integer) {
//系统会把map集合的每个Entry'传递给方法的参数, Entry的键传递第一个参数, Entry的值是第二个参数
System.out.println( s + " : " + integer);
}
});*/
BiConsumer接口只需要重写一个抽象方法,可以使用Lambda表达式
map.forEach((k,v) -> System.out.println( k + " : " + v ));
//10 在遍历map集合中的数据时, 可以使用foreach循环遍历Map的相应的键,或者值,或者Entry
for (String key : map.keySet()) { //遍历 map.keySet() 方法返回的Set集合
//遍历map的键
System.out.println( key + " ---> " + map.get(key) );
}
//遍历map的values()
for (Integer value : map.values()) {
System.out.print(value + " ");
}
System.out.println();
//遍历map.entrySet()所有的entry
for (Map.Entry<String, Integer> entry : map.entrySet()) {
//System.out.println(entry);
//Entry就是一个键值对, Entry有getKey()返回键, getValue()返回值
System.out.println( entry.getKey() + " : " + entry.getValue());
}
//11 注意: map.keySet(), map.values(), map.entrySet()这三个方法返回的是Map集合中相应数据的映射(缓存),这三个方法并没有创建新的集合, 从这些集合中删除数据, 其实就是把Map集合中的数据给删除了
for (Iterator<String> iterator = keySet.iterator(); iterator.hasNext(); ) {
String next = iterator.next();
//迭代遍历所有的键,如果键以z开始就删除
if ( next.startsWith("z")){
iterator.remove();
}
}
System.out.println(map); //{lisi=66, hanyi=99, wangwu=80}
//迭代遍历map.values()所有值的集合
for (Iterator<Integer> iterator = map.values().iterator(); iterator.hasNext(); ) {
Integer next = iterator.next();
if ( next > 70 ){
iterator.remove();
}
}
System.out.println( map.values() );
System.out.println( map );
HashMap工作原理
HashMap如何解决哈希冲突? 采用拉链法
equals不相等的两个对象计算出来的hash值一样,称为哈希冲突(哈希碰撞)
根据哈希约定,如果两个对象equals相等,则这两个对象的哈希码应该一样两个对象equals不相等,它们的哈希码可能相等哈希码不相等,经过hash函数计算出来的哈希值可能相等哈希值不相等,计算出来的数组下标可能相等int x = 15, y = 15, z= 25;x等于y, 不管进行什么运算, x与y运算结果应该是一样的x与z不相等, 现在对 10 求余, 它们的余数是相等的
JDK8对HashMap做了哪些改进? 新增结点插入链表的尾部 当链表中结点数量超过8个会尝试转换为红黑树
在JDK7之前 , HashMap新增结点插入链表头部的
当链表中结点数量超过8个时, 如果数组长度小于64时, 先对数组扩容 数组长度大于等于64时, 会把单向链表转换为红黑树目的就是为了提高查询效率其实在HashMap中把链表转换为红黑树的概率小于千万分之一
当红黑树中结点数量小于6个时会再转换为单向链表
HashMap源码
HashTable
HashTable底层数据结构是哈希表, 它是线程安全的, HashMap不是线程安全的
初始化容量是 11, HashMap初始化容量是16
加载因子0.75, 当键值对的数量 > 数组长度*加载因子时, 就扩容
按 2倍 + 1 扩容, HashMap按2倍大小扩容
可以指定初始化容量, Hashmap 会把初始化容量调整为2的幂次方
HashTable的键值都不允许为null, HashMap的键值是可以为null的
练习
1 定义Map保存 向集合中添加一组数据 查看体育老师是谁 查看是否开设 劳动课 修改英语老师为 刘老师 查看总共开设了多少课程 查看都有哪些老师有教学任务
import java.util.HashMap;
import java.util.Map;
public class Test01 {
public static void main(String[] args) {
//1 定义Map保存<课程名称,老师姓名>
Map<String,String> map = new HashMap<>();
// 向集合中添加一组数据
map.put("语文", "刘老师");
map.put("数学", "王老师");
map.put("英语", "张老师");
map.put("历史", "赵老师");
map.put("体育", "周老师");
map.put("美术", "郑老师");
map.forEach((k,v) -> System.out.println(k + " : " + v ));
// 查看体育老师是谁, 调用get(k)返回键对应的value值
System.out.println(map.get("体育"));
// 查看是否开设 劳动课, 课程是以键的身份存在的,
System.out.println( map.containsKey("劳动"));
// 修改英语老师为 刘老师
map.replace("英语", "Liu");
// 查看总共开设了多少课程
System.out.println( map.keySet());
// 查看都有哪些老师有教学任务
System.out.println(map.values());
}
}
2 定义Map保存 向集合中添加一组数据<课程名称,老师姓名> 查看3号 删除4号 修改5号 删除所有不及格同学
/**
* Map的value值是自定义类型对象
*/
public class Test02 {
public static void main(String[] args) {
//2 定义Map保存<编号, Student对象>
Map<Integer,Student> map = new HashMap<>();
// 向集合中添加一组数据
map.put(1, new Student("hanyi", 80));
map.put(2, new Student("liuer", 50));
map.put(3, new Student("zhangsan", 30));
map.put(4, new Student("lisi", 90));
map.put(5, new Student("wangwu", 80));
map.put(6, new Student("zholiu", 60));
map.put(7, new Student("chenqi", 70));
map.put(8, new Student("zhuba", 20));
for (Map.Entry<Integer, Student> entry : map.entrySet()) {
System.out.println(entry);
}
// 查看3号
System.out.println( map.get(3) );
// 删除4号
map.remove(4);
// 修改5号
map.replace(5, new Student("sunjiu", 50));
map.forEach((k,v) -> System.out.println( k + " : " + v));
// 删除所有不及格同学
for (Iterator<Student> iterator = map.values().iterator(); iterator.hasNext(); ) {
Student next = iterator.next();
if ( next.score < 60 ){
iterator.remove();
}
}
System.out.println("------------删除不及格同学后--------------");
for (Integer key : map.keySet()) {
System.out.println(key + " : " + map.get(key));
}
}
//定义学生类
static class Student{
String name;
int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", score=" + score +
'}';
}
}
}
3 定义Map保存模拟用户注册与登录,程序运行界面------------------------欢迎来到动力商城------------------------------ 1 注册 2 登录 3 退出 请输入你的操作: 1=注册==== 请输入用户名: lisi 该用户名已存在,请重新输入:wangwu 请输入密码: 123 注册成功------------------------欢迎来到动力商城------------------------------ 1 注册 2 登录 3 退出请输入你的操作: 2=登录==== 请输入用户名: lisi 请输入密码: 123 用户名或密码不正确,
程序运行结束退出就不保存数据了,所以需要套个循环来让他一直运行,ctrl+AIt+T套个while的循环结构
/**
* 模拟用户注册与登录
*/
public class Test03Login {
public static void main(String[] args) {
// 定义Map保存<用户名,密码>模拟用户注册与登录,程序运行界面
Map<String,String> map = new HashMap<>();
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("------------------------欢迎来到动力商城------------------------------");
System.out.println(" 1 注册 2 登录 3 退出");
System.out.println("请输入你的操作: ");
int choice = sc.nextInt();
if ( choice == 1) {
System.out.println("===================注册======================");
System.out.println(" 请输入用户名: ");
String name = sc.next();
//当用户名已存在提示重新输入
while (map.containsKey(name) ) {
System.out.println(" 该用户名已存在, 请重新输入: ");
name = sc.next();
}
System.out.println(" 请输入密码:");
String pwd = sc.next();
//注册
if ( map.put(name,pwd) == null ) {
System.out.println(" 注册成功 ");
}else {
System.out.println("注册失败");
}
}else if ( choice == 2) {
System.out.println("===================登录======================");
System.out.println(" 请输入用户名: ");
String name = sc.next();
System.out.println(" 请输入密码:");
String pwd = sc.next();
//判断登录是否成功
if ( pwd.equals(map.get(name))){
System.out.println("登录 成功");
}else {
System.out.println("用户名或密码不正确");
}
}
}
}
}
多个方法需要用同一个参数,可以通过传参数,也可以把这个变量定义为成员变量,这个方法定义为静态方法 ctrl+shift+M抽取方法
/**
* 模拟用户注册与登录
*/
public class Test04Login {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("------------------------欢迎来到动力商城------------------------------");
System.out.println(" 1 注册 2 登录 3 退出");
System.out.println("请输入你的操作: ");
int choice = sc.nextInt();
if (choice == 1) {
register(sc); //注册
} else if (choice == 2) {
login(sc); //登录
}
}
}
// 定义Map保存<用户名,密码>模拟用户注册与登录,程序运行界面
private static Map<String, String> map = new HashMap<>();
private static void login(Scanner sc) {
System.out.println("===================登录======================");
System.out.println(" 请输入用户名: ");
String name = sc.next();
System.out.println(" 请输入密码:");
String pwd = sc.next();
//判断登录是否成功
if (pwd.equals(map.get(name))) {
System.out.println("登录 成功");
} else {
System.out.println("用户名或密码不正确");
}
}
private static void register(Scanner sc) {
System.out.println("===================注册======================");
System.out.println(" 请输入用户名: ");
String name = sc.next();
//当用户名已存在提示重新输入
while (map.containsKey(name)) {
System.out.println(" 该用户名已存在, 请重新输入: ");
name = sc.next();
}
System.out.println(" 请输入密码:");
String pwd = sc.next();
//注册
if (map.put(name, pwd) == null) {
System.out.println(" 注册成功 ");
} else {
System.out.println("注册失败");
}
}
}
工作中的业务流程---------类似于分包
/**
* 模拟用户注册与登录
*/
public class Test05Login {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("------------------------欢迎来到动力商城------------------------------");
System.out.println(" 1 注册 2 登录 3 退出");
System.out.println("请输入你的操作: ");
int choice = sc.nextInt();
if (choice == 1) {
register(sc); //注册
} else if (choice == 2) {
login(sc); //登录
}
}
}
// 定义登录业务对象
private static UserLoginService userLoginService = new UserLoginService();
private static void login(Scanner sc) {
System.out.println("===================登录======================");
System.out.println(" 请输入用户名: ");
String name = sc.next();
System.out.println(" 请输入密码:");
String pwd = sc.next();
//判断登录是否成功
if (userLoginService.login(name, pwd)) {
System.out.println("登录 成功");
} else {
System.out.println("用户名或密码不正确");
}
}
private static void register(Scanner sc) {
System.out.println("===================注册======================");
System.out.println(" 请输入用户名: ");
String name = sc.next();
//当用户名已存在提示重新输入
while (userLoginService.containsName(name)) {
System.out.println(" 该用户名已存在, 请重新输入: ");
name = sc.next();
}
System.out.println(" 请输入密码:");
String pwd = sc.next();
//注册
if (userLoginService.register(name, pwd)) {
System.out.println(" 注册成功 ");
} else {
System.out.println("注册失败");
}
}
}
//定义用户注册业务类
class UserLoginService {
//定义Map保存<用户名,密码>
private Map<String, String> map = new HashMap<>();
//提供方法判断用户名是否存在
public boolean containsName(String name) {
return map.containsKey(name);
}
//提供方法注册
public boolean register(String name, String pwd) {
return map.put(name, pwd) == null;
}
//提供方法登录
public boolean login(String name, String pwd) {
if (pwd == null) return false;
return pwd.equals(map.get(name));
}
}
4 有字符串:adfkjalkjfglakjglkajsdflkjadslkfjadslkjflakdsjflkadsjlfkjaslkfjdalkjgflkagjlfhjglkafdhlkjadslkadjsfsfjkladsfja统计字符串中每个字符出现的次数, 把保存到Map集合中
/**
* 统计字符串中每个 字符出现的次数
*/
public class Test06Statics {
public static void main(String[] args) {
String str = "asasdfaadsfagahjdhgjhdfahgjkhjkdfhgjkhajkgfhalkdsjgfkljadsfklgjdgslkj";
//定义Map保存<字符,次数>
Map<Character, Integer> map = new HashMap<>();
//遍历字符串的每个字符
for (int i = 0; i < str.length(); i++) {
char cc = str.charAt(i);
//System.out.println( cc );
//如果map的键不包含字符cc
if (!map.containsKey(cc)) {
map.put(cc, 1);
} else {
//map的键包含字符cc, 从map集合中把cc之前出现的次数取出来
int count = map.get(cc);
//把map集合中cc的次数修改为count+1
map.replace(cc, count + 1);
}
}
map.forEach((k, v) -> System.out.println(k + "的次数为:" + v));
}
}
hgjkhajkgfhalkdsjgfkljadsfklgjdgslkj";
//定义Map保存<字符,次数>
Map<Character, Integer> map = new HashMap<>();
//遍历字符串的每个字符
for (int i = 0; i < str.length(); i++) {
char cc = str.charAt(i);
//System.out.println( cc );
//如果map的键不包含字符cc
if (!map.containsKey(cc)) {
map.put(cc, 1);
} else {
//map的键包含字符cc, 从map集合中把cc之前出现的次数取出来
int count = map.get(cc);
//把map集合中cc的次数修改为count+1
map.replace(cc, count + 1);
}
}
map.forEach((k, v) -> System.out.println(k + "的次数为:" + v));
}
}