day06-Lambda+Map+HashMap

day06-Lambda+Map+HashMap

学习任务

1 掌握Lambda表达式的语法

2 掌握Map的基本操作

3 记住HashMap工作原理

4 了解HashTable特点

Lambda表

文章目录

达式

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集合是按对的形式存储数据
02 Map集合 03 Map继承 04 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工作原理

05 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个时会再转换为单向链表

06 红黑树
HashMap源码
07 HashMap源码分析 08 put流程图 09 resize流程

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

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值