在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表达式本质上是一段匿名内部类,也可以是一段可以传递的代码

  1. //匿名内部类
  2. Comparator<Integer> cpt = new Comparator<Integer>() {
  3. @Override
  4. public int compare(Integer o1, Integer o2) {
  5. return Integer.compare(o1,o2);
  6. }
  7. };
  8. TreeSet<Integer> set = new TreeSet<>(cpt);
  9. System.out.println("=========================");
  10. //使用lambda表达式
  11. Comparator<Integer> cpt2 = (x,y) -> Integer.compare(x,y);
  12. TreeSet<Integer> set2 = new TreeSet<>(cpt2);

只需要一行代码,极大减少代码量!!

  1. // 筛选颜色为红色
  2. public List<Product> filterProductByColor(List<Product> list){
  3. List<Product> prods = new ArrayList<>();
  4. for (Product product : list){
  5. if ("红色".equals(product.getColor())){
  6. prods.add(product);
  7. }
  8. }
  9. return prods;
  10. }
  11. // 筛选价格小于8千的
  12. public List<Product> filterProductByPrice(List<Product> list){
  13. List<Product> prods = new ArrayList<>();
  14. for (Product product : list){
  15. if (product.getPrice() < 8000){
  16. prods.add(product);
  17. }
  18. }
  19. return prods;
  20. }

我们发现实际上这些过滤方法的核心就只有if语句中的条件判断,其他均为模版代码,每次变更一下需求,都需要新增一个方法,然后复制黏贴,假设这个过滤方法有几百行,那么这样的做法难免笨拙了一点。如何进行优化呢?

优化一:使用设计模式

定义一个MyPredicate接口

  1. public interface MyPredicate <T> {
  2. boolean test(T t);
  3. }

如果想要筛选颜色为红色的商品,定义一个颜色过滤类

  1. public class ColorPredicate implements MyPredicate <Product> {
  2. private static final String RED = "红色";
  3. @Override
  4. public boolean test(Product product) {
  5. return RED.equals(product.getColor());
  6. }

定义过滤方法,将过滤接口当做参数传入,这样这个过滤方法就不用修改,在实际调用的时候将具体的实现类传入
即可。

  1. public List<Product> filterProductByPredicate(List<Product> list,MyPredicate<Product> mp){
  2. List<Product> prods = new ArrayList<>();
  3. for (Product prod : list){
  4. if (mp.test(prod)){
  5. prods.add(prod);
  6. }
  7. }
  8. return prods;
  9. }

例如,如果想要筛选价格小于8000的商品,那么新建一个价格过滤类既可

  1. public class PricePredicate implements MyPredicate<Product> {
  2. @Override
  3. public boolean test(Product product) {
  4. return product.getPrice() < 8000;
  5. }
  6. }

这样实现的话可能有人会说,每次变更需求都需要新建一个实现类,感觉还是有点繁琐呀,那么再来优化一下

优化二:使用匿名内部类

定义过滤方法:

  1. public List<Product> filterProductByPredicate(List<Product> list,MyPredicate<Product> mp){
  2. List<Product> prods = new ArrayList<>();
  3. for (Product prod : list){
  4. if (mp.test(prod)){
  5. prods.add(prod);
  6. }
  7. }
  8. return prods;
  9. }

调用过滤方法的时候:

  1. // 按价格过滤
  2. public void test2(){
  3. filterProductByPredicate(proList, new MyPredicate<Product>() {
  4. @Override
  5. public boolean test(Product product) {
  6. return product.getPrice() < 8000;
  7. }
  8. });
  9. }
  10. // 按颜色过滤
  11. public void test3(){
  12. filterProductByPredicate(proList, new MyPredicate<Product>() {
  13. @Override
  14. public boolean test(Product product) {
  15. return "红色".equals(product.getColor());
  16. }
  17. });
  18. }

使用匿名内部类,就不需要每次都新建一个实现类,直接在方法内部实现。看到匿名内部类,不禁想起了Lambda表达式。

优化三:使用lambda表达式

定义过滤方法:

  1. public List<Product> filterProductByPredicate(List<Product> list,MyPredicate<Product> mp){
  2. List<Product> prods = new ArrayList<>();
  3. for (Product prod : list){
  4. if (mp.test(prod)){
  5. prods.add(prod);
  6. }
  7. }
  8. return prods;
  9. }

使用lambda表达式进行过滤

  1. @Test
  2. public void test4(){
  3. List<Product> products = filterProductByPredicate(proList, (p) -> p.getPrice() < 8000);
  4. for (Product pro : products){
  5. System.out.println(pro);
  6. }
  7. }

在jdk1.8中还有更加简便的操作 Stream API

优化四:使用Stream API

甚至不用定义过滤方法,直接在集合上进行操作

  1. // 使用jdk1.8中的Stream API进行集合的操作
  2. @Test
  3. public void test(){
  4. // 根据价格过滤
  5. proList.stream()
  6. .fliter((p) -> p.getPrice() <8000)
  7. .limit(2)
  8. .forEach(System.out::println);
  9. // 根据颜色过滤
  10. proList.stream()
  11. .fliter((p) -> "红色".equals(p.getColor()))
  12. .forEach(System.out::println);
  13. // 遍历输出商品名称
  14. proList.stream()
  15. .map(Product::getName)
  16. .forEach(System.out::println);
  17. }

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(){

    1. changeStr("hello",(str) -> System.out.println(str));

    }

    /**

    • Consumer 消费型接口
    • @param str
    • @param con */ public void changeStr(String str, Consumer con){ con.accept(str); }

```

3. 方法引用和构造器调用

4. Stream API

5. 接口中的默认方法和静态方法

6. 新时间日期API