JDK8新特性
面试官经常会问到新版JDK新的特性, 尤其是JDK8的特性。
下面将首先讲解JDK版本发布情况,概括性介绍JDK8的主要新的特征。
主要包括:
新的语言特性
集合对象的修改
JVM新特性
HashMap的修改
JDK8 引入了很多非常实用和长期的影响
JDK8引入新的语法特性,比如Lambda表达式,默认方法,方法引用,新增新的日期处理类
JDK8为Collection新增Stream流式接口, 修改HashMap和ConcurrentHashMap实现
JDK8修改了JVM内存模型, 实用metaSpace代替永久代
JDK新增并发接口和实现, 包括新增CompletableFuture、为ConcurrentHashMap新增支持Stream方法、新增StampedLock
下面介绍几个面试过程经常被问到的几个新特性
Lambda表达式、方法引用和默认方法
1. Lambda表达式
Lambda表达式允许把函数作为一个方法的参数。
有几种常见的Lambda表达式:
// 1. 不需要参数,返回值为 5 () -> 5 // 2. 接收一个参数(数字类型),返回其2倍的值 x -> 2 * x // 3. 接受2个参数(数字),并返回他们的差值 (x, y) -> x – y // 4. 接收2个int型整数,返回他们的和 (int x, int y) -> x + y // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void) (String s) -> System.out.print(s)复制代码
2. 方法引用
JDK8支持了四种方式方法引用
类型方法引用
引用静态方法ContainingClass::staticMethodName
引用特定对象的实例方法containingObject::instanceMethodName
引用特定类型的任意对象的实例方法String::compareToIngoreCase
引用构造函数ClassName::new
3. 默认方法和静态方法
JDK1.8支持在接口中定义默认方法和静态方法, 默认方法可以被接口实现引用。
package defaultmethods; import java.time.*;public interface TimeClient { voidsetTime(int hour, int minute, int second); voidsetDate(int day, int month, int year); voidsetDateAndTime(int day, int month, int year, int hour, int minute, int second); LocalDateTime getLocalDateTime(); // 静态方法 static ZoneId getZoneId (String zoneString) { try {returnZoneId.of(zoneString); } catch (DateTimeException e) { System.err.println("Invalid time zone: "+ zoneString +"; using default time zone instead.");returnZoneId.systemDefault(); } } // 默认方法 default ZonedDateTime getZonedDateTime(String zoneString) {returnZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString)); }}复制代码
Colletion的修改
JDK1.8增强了Collection FrameWork, 支持了lambda, 流和聚合操作。
改动有两个方面:
支持了lambda, 流和聚合操作
改进的类型推断
改进的类型推断
Java编译器利用目标类型来推断通用方法调用的类型参数。
考虑以下示例:
List stringList = new ArrayList <>();stringList.add("A");stringList.addAll(Arrays.asList());复制代码
Java管理扩展(JMX)提供了对诊断命令的远程访问。
目前,不考虑泛型,该方法addAll将Collection实例作为其参数,然后该方法Arrays.asList返回一个List实例。这是有效的,因为List是的子类型Collection。
现在考虑泛型,的目标类型addAll为Collection<? extends String>,并Arrays.asList返回一个List实例。在此示例中,Java SE 8编译器可以推断类型变量的T值为String。编译器从目标类型推断出这一点Collection<? extends String>。
Java SE 7和更早版本的编译器不接受此代码,因为它们不使用目标类型来推断方法调用参数的类型。例如,Java SE 7编译器生成类似于以下内容的错误消息:
error: no suitable method foundforaddAll(List) ...method List.addAll(Collection) is not applicable (actual argument List cannot be converted to Collection by method invocation conversion)复制代码
因此,在Java编译器无法推断类型的情况下,必须使用显式指定类型变量的值。例如,以下在Java SE 7中有效:
List stringList = new ArrayList <>();stringList.add(“ A”);stringList.addAll(Arrays. asList());复制代码
JVM新特性
JDK8在JVM中修改重要有:
新增JVM工具:jdeps提供了用于分析类文件的命令行工具。
使用metaSpace代替永久区
新增NMT(Native Memeory Trace)本地内存跟踪器,参见NMT
HashMap变化
JDK8优化了HashMap的实现, 主要优化点包括:
将链表方式修改成链表或者红黑树的形式
修改resize的过程,解决JDK7在resize在并发场景下死锁的隐患
JDK1.7存储使用Entry数组, JDK8使用Node或者TreeNode数组存储
当链表长度大于8是链表的存储结构会被修改成红黑树的形式。
查询效率从O(N)提升到O(logN)。链表长度小于6时,红黑树的方式退化成链表。
JDK7链表插入是从链表头部插入, 在resize的时候会将原来的链表逆序。
JDK8插入从链表尾部插入, 因此在resize的时候仍然保持原来的顺序。