1 数据结构的更新

1.1 HashMap 的数据结构更新
1.2 ConcurrentHashMap 的数据结构更新

2 hotspot JVM 内存结构更新

3 函数式接口

4 Lambda 表达式

5 Stream API

一、数据结构的更新

1.1 HashMap 的数据结构更新

在 jdk1.8前 HashMap 底层是用数组 + 链表来实现的,而在 jdk1.8 后 HashMap 采用数组 + 链表 + 红黑树进行实现。

下面先看看 jdk1.7 的数据结构:
在这里插入图片描述
(网上借用的图片:https://blog.csdn.net/striveb/article/details/84657326)
HashMap 的底层实际上是一个 Entry[] 数组,该数组存放着一个个 Entry 实体,该实体包括 key,value,hash(key对应的 hash 值),以及下一个 Entry(形成链表)
在这里插入图片描述
HashMap 采用链地址法(拉链法)解决 hash 碰撞,当链的长度越来越长时,HashMap 的查询时间复杂度会趋向于 O(n),因为每次查找时,先计算 key 的hash值,根据 hash 值找到对应的桶(即数组的位置),假如在第一个位置查找不到时,需要遍历这个桶中的链表,先比较 hash 值,hash值相等时,再用 equals 方法比较(因为 hash 算法的原因,hash 值相等的两个对象不一定是同一个对象,equals 方法相等的对象即一定为相同的一个对象,为什么要这样比较可以查看一下 hash 和 equals 方法的文章),这样查找的效率是比较低的。

为了加快查询效率,在 jdk1.8 中,当链表的长度大于 8 时,将会把该链表转换为红黑树(平衡的二叉搜索树),查询时间复杂度会变成 O(log2N)

因为 HashMap的改变,相应的 Set 集合的数据结构也会改变,因为 Set 的底层也是用 HashMap 进行实现的(key 为存放的值,value为同一个 Object 对象)。

1.2 ConcurrentHashMap 的数据结构更新

在 jdk1.8 前,ConcurrentHashMap 是采用分段锁进行实现的,底层是一个Segment 数组,Segment 数组里面存放着一个个 Segment,因为 Segment 继承了 ReentrantLock 类,所以该类可以当做一个锁,同时 Segment 是一个小的 Hash 表,即存放着一个个 HashEntry[] 数组,HashEntry[] 存放着 Entry 类。
在这里插入图片描述
(图片出处:https://blog.csdn.net/justloveyou_/article/details/72783008)
在jdk1.7中ConcurrentHashMap使用锁分段技术提高并发访问效率。首先将数据分成一段一段地存储,然后给每一段数据配一个锁,当一个线程占用锁访问其中一段数据时,其他段的数据也能被其他线程访问。
在 jdk 1.8 后ConcurrentHashMap 取消了分段锁机制,利用 CAS + Synchronized 来保证并发更新的安全,底层依然采用数组+链表+红黑树的存储结构,ConcurrentHashMap 是线程安全的,并且它锁的粒度变的更细,在 jdk1.7 中它锁的是一个 Segment(一个分段),在 1.8 中它只是锁住一个桶的对象,并发效率更高。

2 Hotspot JVM 内存结构更新

在 jdk1.8 前,Oracle的 HotSpot JVM 中的堆逻辑上分为 年轻代、老年代、永久代三部分,而 jdk1.8 时,HotSpot JVM 的永久代被使用物理内存的元空间取代。

3 函数式接口

在jdk1.8 时,可以用 @FunctionalInterface 注解标注一个接口,标识它为一个函数式接口。那什么是函数式接口?
函数式接口就是一个只能含有一个抽象方法的接口,若有多个抽象将会报错,同时在 jdk1.8 中,可以使用 default 关键字标注一个方法,该方法即可在接口中实现。
在这里插入图片描述
为了方便开发,Java 8 提供了四大内置的函数式接口,方便配置 Lambda 表达式进行使用。
在这里插入图片描述

4 Lambda 表达式

Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符或剪头操作符。它将 Lambda 分为两个部分:
左侧:指定了 Lambda 表达式需要的所有参数
右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能。

语法格式一:

无参数,无返回值

() -> System.out.println("Hello Lambda!");
语法格式二:

有一个参数,并且无返回值

(x) -> System.out.println(x)
语法格式三:

若只有一个参数,小括号可以省略不写

x -> System.out.println(x)
语法格式四:

有两个以上的参数,有返回值,并且 Lambda 体中有多条语句

		Comparator<Integer> com = (x, y) -> {
			System.out.println("函数式接口");
			return Integer.compare(x, y);
		};
语法格式五:

若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写

Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
语法格式六:

Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”

(Integer x, Integer y) -> Integer.compare(x, y);

下面看到一个创建线程的例子:

	@Test
	public void test1(){
		int num = 0;//jdk 1.7 前,必须是 final
		//正常实现方式
		Runnable r = new Runnable() {
			@Override
			public void run() {
				System.out.println("Hello World!" + num);
			}
		};
		
		r.run();
		
		System.out.println("-------------------------------");
		//利用 Lambda表达式的实现方式
		Runnable r1 = () -> System.out.println("Hello Lambda!");
		r1.run();
	}

例子二:

	//普通实现方式
    @Test
    public void test8(){
        Comparator<Integer> com = new Comparator<Integer>() {
            @Override
            public int compare(Integer x, Integer y) {
                return Integer.compare(x, y);
            }
        } ;
    }
	
	//Lambda 表达式
	@Test
    public void test7(){
        Comparator<Integer> com = (x, y) -> {
            System.out.println("函数式接口");
            return Integer.compare(x, y);
        };
    }

Lambda 表达式依赖于接口,每个 Lambda 表达式都对应着一个函数式接口,Java 8为我们内置了四大函数式接口以及其子类,如:Consumer、Supplier、Function、Predicate。其子类有(这只是一部分):
在这里插入图片描述
暂时更新这么多…,java 8 还有很多新特性这里只有一部分,有兴趣的可以看看这个视频,有空再更新:
链接:https://pan.baidu.com/s/1gfjkxibxL4eog9JulmVvyA
提取码:3bhi
需要的可以看看,尚硅谷的,感觉讲的还可以。

Logo

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

更多推荐