在jdk1.8中对hashMap等map集合的数据结构优化。hashMap数据结构的优化
原来的hashMap采用的数据结构是哈希表(数组+链表),hashMap默认大小是16,一个0-15索引的数组,如何往里面存储元素,首先调用元素的hashcode
方法,计算出哈希码值,经过哈希算法算成数组的索引值,如果对应的索引处没有元素,直接存放,如果有对象在,那么比较它们的equals方法比较内容
如果内容一样,后一个value会将前一个value的值覆盖,如果不一样,在1.7的时候,后加的放在前面,形成一个链表,形成了碰撞,在某些情况下如果链表
无限下去,那么效率极低,碰撞是避免不了的
加载因子:0.75,数组扩容,达到总容量的75%,就进行扩容,但是无法避免碰撞的情况发生
在1.8之后,在数组+链表+红黑树来实现hashmap,当碰撞的元素个数大于8时 & 总容量大于64,会有红黑树的引入
除了添加之后,效率都比链表高,1.8之后链表新进元素加到末尾
ConcurrentHashMap (锁分段机制),concurrentLevel,jdk1.8采用CAS算法(无锁算法,不再使用锁分段),数组+链表中也引入了红黑树的使用
1. Lambda表达式
Lambda表达式本质上是一段匿名内部类,也可以是一段可以传递的代码
//匿名内部类
Comparator<Integer> cpt = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
TreeSet<Integer> set = new TreeSet<>(cpt);
System.out.println("=========================");
//使用lambda表达式
Comparator<Integer> cpt2 = (x,y) -> Integer.compare(x,y);
TreeSet<Integer> set2 = new TreeSet<>(cpt2);
只需要一行代码,极大减少代码量!!
// 筛选颜色为红色
public List<Product> filterProductByColor(List<Product> list){
List<Product> prods = new ArrayList<>();
for (Product product : list){
if ("红色".equals(product.getColor())){
prods.add(product);
}
}
return prods;
}
// 筛选价格小于8千的
public List<Product> filterProductByPrice(List<Product> list){
List<Product> prods = new ArrayList<>();
for (Product product : list){
if (product.getPrice() < 8000){
prods.add(product);
}
}
return prods;
}
我们发现实际上这些过滤方法的核心就只有if语句中的条件判断,其他均为模版代码,每次变更一下需求,都需要新增一个方法,然后复制黏贴,假设这个过滤方法有几百行,那么这样的做法难免笨拙了一点。如何进行优化呢?
优化一:使用设计模式
定义一个MyPredicate接口
public interface MyPredicate <T> {
boolean test(T t);
}
如果想要筛选颜色为红色的商品,定义一个颜色过滤类
public class ColorPredicate implements MyPredicate <Product> {
private static final String RED = "红色";
@Override
public boolean test(Product product) {
return RED.equals(product.getColor());
}
定义过滤方法,将过滤接口当做参数传入,这样这个过滤方法就不用修改,在实际调用的时候将具体的实现类传入
即可。
public List<Product> filterProductByPredicate(List<Product> list,MyPredicate<Product> mp){
List<Product> prods = new ArrayList<>();
for (Product prod : list){
if (mp.test(prod)){
prods.add(prod);
}
}
return prods;
}
例如,如果想要筛选价格小于8000的商品,那么新建一个价格过滤类既可
public class PricePredicate implements MyPredicate<Product> {
@Override
public boolean test(Product product) {
return product.getPrice() < 8000;
}
}
这样实现的话可能有人会说,每次变更需求都需要新建一个实现类,感觉还是有点繁琐呀,那么再来优化一下
优化二:使用匿名内部类
定义过滤方法:
public List<Product> filterProductByPredicate(List<Product> list,MyPredicate<Product> mp){
List<Product> prods = new ArrayList<>();
for (Product prod : list){
if (mp.test(prod)){
prods.add(prod);
}
}
return prods;
}
调用过滤方法的时候:
// 按价格过滤
public void test2(){
filterProductByPredicate(proList, new MyPredicate<Product>() {
@Override
public boolean test(Product product) {
return product.getPrice() < 8000;
}
});
}
// 按颜色过滤
public void test3(){
filterProductByPredicate(proList, new MyPredicate<Product>() {
@Override
public boolean test(Product product) {
return "红色".equals(product.getColor());
}
});
}
使用匿名内部类,就不需要每次都新建一个实现类,直接在方法内部实现。看到匿名内部类,不禁想起了Lambda表达式。
优化三:使用lambda表达式
定义过滤方法:
public List<Product> filterProductByPredicate(List<Product> list,MyPredicate<Product> mp){
List<Product> prods = new ArrayList<>();
for (Product prod : list){
if (mp.test(prod)){
prods.add(prod);
}
}
return prods;
}
使用lambda表达式进行过滤
@Test
public void test4(){
List<Product> products = filterProductByPredicate(proList, (p) -> p.getPrice() < 8000);
for (Product pro : products){
System.out.println(pro);
}
}
优化四:使用Stream API
甚至不用定义过滤方法,直接在集合上进行操作
// 使用jdk1.8中的Stream API进行集合的操作
@Test
public void test(){
// 根据价格过滤
proList.stream()
.fliter((p) -> p.getPrice() <8000)
.limit(2)
.forEach(System.out::println);
// 根据颜色过滤
proList.stream()
.fliter((p) -> "红色".equals(p.getColor()))
.forEach(System.out::println);
// 遍历输出商品名称
proList.stream()
.map(Product::getName)
.forEach(System.out::println);
}
Lmabda表达式的语法总结: () -> ();
前置 | 语法 |
---|---|
无参数无返回值 | () -> System.out.println(“Hello World”) |
有一个参数无返回值 | (x) -> System.out.println(x) |
有且只有一个参数无返回值 | x -> System.out.println(x) |
有多个参数,有返回值,有多条lambda体语句 | (x,y) -> {System.out.println(“xxx”);return xxxx;}; |
有多个参数,有返回值,只有一条lambda体语句 | (x,y) -> xxxx |
口诀:左右遇一省括号,左侧推断类型省
注:当一个接口中存在多个抽象方法时,如果使用lambda表达式,并不能智能匹配对应的抽象方法,因此引入了函数式接口的概念
2. 函数式接口
函数式接口的提出是为了给Lambda表达式的使用提供更好的支持。
什么是函数式接口?
简单来说就是只定义了一个抽象方法的接口(Object类的public方法除外),就是函数式接口,并且还提供了注解:@FunctionalInterface
常见的四大函数式接口
Consumer 《T》:消费型接口,有参无返回值 ```java @Test public void test(){
changeStr("hello",(str) -> System.out.println(str));
}
/**
- Consumer
消费型接口 - @param str
- @param con
*/
public void changeStr(String str, Consumer
con){ con.accept(str); }
```