在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>() {@Overridepublic 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 = "红色";@Overridepublic 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> {@Overridepublic 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>() {@Overridepublic boolean test(Product product) {return product.getPrice() < 8000;}});}// 按颜色过滤public void test3(){filterProductByPredicate(proList, new MyPredicate<Product>() {@Overridepublic 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表达式进行过滤
@Testpublic 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进行集合的操作@Testpublic 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); }
```
