课程内容:
-
Map集合常见的面试题
-
Lambda表达式
-
方法引用
-
Optional类
Map集合常见的面试题?
-
HashMap和Hashtable之间的区别?
同步特性不同:
Hashtable同一时间允许一个线程进行访问 效率较低 但是不会出现并发错误
HashMap同一时间允许多个线程进行访问 效率较高 但是可能会出现并发错误
jdk5.0开始 集合的工具类里面提供一个方法 将线程不安全的HashMap变成线程安全的Map集合 于是HashTable渐渐被淘汰了
Map map = Collections.synchronizedMap(HashMap对象)
对null容忍度不同
Hashtable无论是主键还是值 都不能传入null 否则触发空指针异常
HashMap无论是主键还是值 都可以传入null 但是由于主键唯一 所以只能输入一个null
分组组数不同
Hashtable默认分11个小组 程序员可以随意的指定
HashMap默认分16个小组 程序员可以随意的指定 但是最终一定会变成2的n次方数
出现的版本不同
Hashtable since jdk1.0
HashMap since jdk1.2 -
HashMap Hashtable ConcurrentHashMap之间的区别?
Hashtable为了追求安全性 只要有一个线程进入哈希表之后 将整个哈希表全部加锁 同一时间最多一个线程进行访问 所以效率很低
HashMap为了追求高效性 不再加锁 因此在多线程的情况下可能会出现并发错误
ConcurrentHashMap为了追求高效性和安全性 采用了锁分离机制 将锁的粒度降低
如果有一个线程进入哈希表 仅仅对该小组加锁 如果新来的线程也想要访问该小组 需要等待
如果新来的线程想要访问未加锁的小组 直接访问 -
在多线程的情况下 HashMap不安全 有什么可以替代的方案?
Hashtable
ConcurrentHashMap
Map map = Collections.synchronizedMap(HashMap对象) -
HashMap在jdk7.0前后的底层变化
HashMap底层基于哈希表实现的
jdk7.0及之前 哈希表由数组 + 链表组成
数组:用来存储表头信息 为了方便元素快速定位应该去到的小组
链表:用来组内添加元素
头插法
jdk8.0开始 哈希表由数组 + 链表 + 二叉树组成
数组:用来存储表头信息 为了方便元素快速定位应该去到的小组
链表:用来组内添加元素
当链表长度 > 8个元素 由链表 转换成 二叉树
当二叉树长度 < 6个元素 由二叉树 转换成 链表
尾插法
Lambda表达式:
-
Lambda表达式其实是一个匿名函数 它允许参数以匿名函数的形式输入进去 用于简化代码
-
jdk8.0出现了一种新的操作符 -> [箭头操作符] 将整个语句分为两个部分
Lambda表达式格式:(...) -> ....
左侧:要覆盖的抽象方法的参数列表
右侧:表示Lambda体 写具体的执行步骤 -
Lambda表达式需要注意:
左侧参数列表只有一个参数的话()可以省略 建议不要省略
左侧参数列表里面的数据类型可以省略 jdk7.0开始 泛型可以自动推断
右侧Lambda体如果只有一句话的话 return和{}可以省略
右侧Lambda体有多句话的话 return和{}不能省略 -
当调用一个方法 发现方法的参数是函数式接口的话 都可以使用Lambda表达式简化
什么是函数式接口?
接口里面只有一个抽象方法 -》 函数式接口 -
jdk8.0开始 新增四大函数式接口
Consumer:消费型接口
抽象方法:accept(x) -> void
Predicate:断言型接口
抽象方法:test(x) -> boolean -
Jdk8.0开始 针对List集合新增:
jdk8.0之前 List集合排序:
Collections.sort(List):自然排序
Collections.sort(List,Comparator):定制排序
jdk8.0开始 List集合新增排序:
list.sort(Comparator);定制排序 -
Jdk8.0针对所有单值集合新增:
forEach((x) -> void):对集合里面的元素进行...处理
removeIf((x) -> boolean):删除集合里面所有符合条件的元素 -
jdk8.0针对Map集合新增的方法
forEach((k,v) -> void):对集合里面的元素进行...处理
jdk8.0 方法引用 是对Lambda表达式的再一种简化的版本
8.0之前 调用方法:
对象.实例方法()
类名.静态方法()
new 构造方法()
8.0开始 调用方法:
1.对象::实例方法
当在Lambda中 将对象.实例方法() 想要改成对象::实例方法
必须满足:
要覆盖的抽象方法参数列表和调用的实例方法的参数列表一致
要覆盖的抽象方法返回类型和调用的实例方法的返回类型一致
2.类名::静态方法
3.类名::实例方法
当在Lambda中 将对象.实例方法() 想要修改类名::实例方法
必须满足:
要覆盖的抽象方法的参数列表比调用的实例方法的参数列表多一个
且抽象方法的第一个参数可以作为实例方法的调用者
要覆盖的抽象方法返回类型和调用的实例方法的返回类型一致
4.构造方法::new
() -> 方法调用 -》 可能修改成 ::的版本
Optional类:jdk8.0新增的一个容器类 专门用来处理空指针异常的类 可以将任意一个可能为空的对象装进Optional容器中 可以有效的避免空指针异常
-
如何将一个对象装进Optional容器中
//如果对象为空 调用of直接出现空指针异常
Optiona<泛型> op = Optional.of(对象);//几乎不用
//如果参数为空 ofNullable不会出现空指针异常 但是返回一个空的容器对象:Optional.empty
Optional<泛型> op = Optional.ofNullable(对象); -
如何从容器里面取值
//在调用get()时 如果容器里面有值 将值返回 如果容器里面没有值 会出现
//NOSuchElementException异常 通常get()搭配isPresent()使用
if(Optional对象.isPresent()){
类型 x = Optional对象.get();
}else{
...
}
//orElse():将容器里面的值返回 如果容器中有值 将值返回 如果容器里面没有值 返回默认值
类型 x = Optional对象.orElse(默认值);