一、新特性简介

  • 1、速度更快
  • 2、代码更少(增加了新的语法Lambda表达式)
  • 3、强大的Stream API
  • 4、便于并行
  • 5、最大化减少空指针异常 Optional
  • 其中,最核心的为Lambda表达式和Stream API

二、Hashmap的实现原理,1.7和1.8有哪些区别

参考链接,通俗易懂:https://www.cnblogs.com/stevenczp/p/7028071.html
JDK1.7中

使用一个Entry数组来存储数据,用key的hashcode取模来决定key会被放到数组里的位置,如果hashcode相同,或者hashcode取模后的结果相同(hash collision),那么这些key会被定位到Entry数组的同一个格子里,这些key会形成一个链表。 在hashcode特别差的情况下,比方说所有key的hashcode都相同,这个链表可能会很长,那么put/get操作都可能需要遍历这个链表 也就是说时间复杂度在最差情况下会退化到O(n)

JDK1.8中

使用一个Node数组来存储数据,但这个Node可能是链表结构,也可能是红黑树结构 如果插入的key的hashcode相同,那么这些key也会被定位到Node数组的同一个格子里。 如果同一个格子里的key不超过8个,使用链表结构存储。 如果超过了8个,那么会调用treeifyBin函数,将链表转换为红黑树。 那么即使hashcode完全相同,由于红黑树的特点,查找某个特定元素,也只需要O(log n)的开销 也就是说put/get的操作的时间复杂度最差只有O(log n)

初始容量16,加载因子0.75的作用是:当HashMap的内存使用空间达到75%后,开始进行扩容。扩容:创建一个新的空数组,长度默认是原数组的2倍。

1.7

  • 1、使用的是数组+ 单链表的数据结构(entry数组和next指针)
  • 2、转移数据方式:头插法,会出现逆序&环形链表死循环问题
  • 3、扩容后数据存储位置的计算方式:直接用hash值和需要扩容的二进制数进行&(index = HashCode(Key) & (Length - 1),最大程度减少hash碰撞)

1.8:

  • 1、使用的是数组+链表+红黑树的数据结构(Node<K,V> 数组和next指针),且JDK8规定,当链表长度大于8时,由单链表转化为红黑树;而当链表长度小于6时,又由红黑树转化为单链表。(转成红黑树后,除添加元素外,其他效率都提高)
  • 2、转移数据方式:尾插法,不会出现逆序&环形链表死循环问题
  • 3、扩容后数据存储位置的计算方式:扩容前的原始位置+扩容的大小值

三、ConcurrentHashMap的实现原理,1.7和1.8有哪些区别

将数据分成一段一段的存储,然后给每一段数据分配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。这就是分段锁的实现原理。有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。这里“按顺序”是很重要的,否则极有可能出现死锁。    参考链接:https://www.jianshu.com/p/d0b37b927c48

二、Lambda表达式

  • Lambda表达式在编译器内部被翻译成私有方法,并派发invokedynamin(动态调用)字节码指令进行调用。(匿名内部类中会编译成一个 .class 文件。)
  • Lambda表达式在Java中又称为闭包或匿名函数。

2.1 什么是Lambda表达式

Lambda表达式是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递),可以写出更简洁、更灵活的代码。

2.2 简单示例

2.3 表达式语法

新的语法 :->
左侧:指定Lambda表达式需要的所有参数
右侧:指定Lambda体,即Lambda表达式要执行的功能

  • 语法格式一:无参,无返回值,Lambda体只需一条语句
    Runnable run2 = () ->  System.out.println("Hello Lambda!");
  • 语法格式二:有一个参数,无返回值
    Consumer<String> fun = (args) ->  System.out.println(args);
  • 语法格式三:只有一个参数,参数的小括号可以省略
    Consumer<String> fun = args ->  System.out.println(args);
  • 语法格式四:2个入参,有返回值
    BinaryOperator<Long> bo = (x, y) -> {
        System.out.println("实现函数接口方法");
        return x + y;
    };
  • 语法格式五:当Lambda体只有一条语句时,return与大括号可以省略
    BinaryOperator<Long> bo = (x, y) -> x + y;
    
  • 语法格式六:参数的数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
    BinaryOperator<Long> bo = (Long x, Long y) -> {
        System.out.println("实现函数接口方法");
        return x + y;
    };

三、函数式接口

只包含一个抽象方法的接口,称为函数式接口。使用@FunctionalInterface 注解

3.1 自定义 函数式接口

3.2 Java内置四大核心  函数式接口

  • 消费性接口:Consumter<T>
  • 供给型接口:Supplier<T>
  • 函数型接口:Function<T, R>
  • 断言型接口:Predicate<T>:适用于做过滤
  • 以及上面四大接口的子接口

四、方法引用和构造器引用

4.1 方法引用

方法引用:使用操作符  ::  将方法名和对象或类的名字分隔开来。
主要使用方式:
对象::实例方法
类::静态方法
类::实例方法

使用注意:实现抽象方法的参数列表必须和方法引用方法的参数列表保存一致。

4.2 实例

例如:(x)-> System.out.println(x);
等同于:System.out::println;

例如:compare(x,y)-> x.equals(y);
等同于:compare(String::equals);

 

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐