JDK8-JDK17新特性总结
约 2545 字大约 8 分钟
JavaJDK
2024-03-02
前言
JDK发展路线
JDK(Java Development Kit)是Java编程语言的软件开发工具包。它包含了Java运行时环境(JRE),以及一系列的Java工具和Java标准类库。JDK的发展和演化影响着Java程序的开发和运行环境。
JDK的发展路线主要可以概括为以下几个主要版本:
JDK 1.0 - JDK 1.2:这个时期的JDK版本主要是语言特性的完善和技术成熟。
JDK 1.3 - JDK 1.4:这个时期引入了一些新的技术,比如JNDI(Java Naming and Directory Interface),Java打包工具(jar),Java Web Start等。
JDK 5.0:这是Java语言发展史上的一个重要版本,引入了一系列重要的新特性,如泛型支持、注解、自动装箱和拆箱、枚举、可变参数等。
JDK 6.0 - JDK 7.0:这个时期的JDK主要是性能优化和小的语言特性增强。
JDK 8.0:这是Java语言发展史上的另一个重要版本,Lambda表达式、流式API、新的日期时间API等特性被引入,这些特性大大提高了开发效率。
JDK 9.0 - JDK 12.0:这个时期JDK引入了一些新的模块化系统、Inter-Switches、JShell等特性。
JDK 13.0 - 最新版本:支持了文本块、edgesite、打包工具的改进等特性。
每个新版本的JDK都会带来新的特性和性能优化,开发者应该关注这些发展,并在开发中适当地使用这些新特性,以提高代码质量和开发效率。
使用如下命令,查看当前 JDK版本
$ java -version
java version "1.8.0_31"
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)
JDK 8及后续版本的每一次迭代,都旨在强化Java语言的功能性、安全性和性能,为开发者提供更为先进、高效的开发工具。掌握这些新特性,是每位Java开发者提升自身技能的必经之路。
JDK 8新特性
1、Lambda表达式 − Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。
Demo
public class Demo {
public static void main(String[] args) {
//开启一个线程
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("(work–life balance");
}
}).start();
}
}
以上代码当我们用new Thread().start()
的方式启动了一个线程时,我们做了以下三件事:
1.定义了一个匿名内部类
2.这个类调用了 Runnable 接口
3.通过 new Runnable(){...}的方式创建了这个类,并重写了该接口的 run() 方法
这个Demo中我们真正关心的并不是new Runnable()这个过程,而是以下两点:
- run() 方法 (参数情况)
- {...}方法体中执行的代码
在以上Demo中我们编写匿名内部类就会感到非常繁琐,针对使用匿名内部类语法冗余的问题,JDK8推出了 Lambda 表达式 Lambda表达式格式
(参数类型 参数名称) -> {
方法体;
return 返回值;
}
格式说明
1.(参数类型 参数名称):参数列表部分
2.{...}:方法体,即要执行的代码部分
3.->:箭头,无实际含义,起到连接参数列表和方法体的作用
表达式实例
// 1. 不需要参数,直接返回
() -> "Java"
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值
(String s) -> System.out.print(s)
省略规则
- 小括号中的参数类型可以省略。
- 如果小括号中只有一个参数,那么可以省略小括号。
- 如果大括号中只有一条语句,那么可以同时省略大括号、return关键字及语句分号。
经过上述的学习,我们可以改造开始的Demo
public class LambdaDemo {
public static void main(String[] args) {
//匿名内部类方式
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("(work–life balance");
}
}).start();
//体验Lambda表达式
new Thread(() ->{
System.out.println("(work–life balance");
}).start();
}
}
总结:Lambda 可以简化匿名内部类,让代码更加精简;Lambda 表达式免去了使用匿名方法的麻烦,并且给予Java强大的函数化的编程能力。
2、函数式编程
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。 函数式接口可以被隐式转换为 lambda 表达式。
2.1 JDK 1.8内置核心函数式接口
Function<T,R>
函数型接口:接受一个类型为T的输入参数,返回一个类型为R的结果(表示接受一个参数并产生结果的函数)。
方法: 方法:R apply(T t);
示例:Function<String, Intger> toLength = s -> s.length();
Consumer<T>
消费型接口:有入参,无返回值(表示接受单个输入参数并且不返回结果的操作)。
方法:void accept(T t);
示例:Consumer<String> printer = s -> System.out.println(s);
Supplier<T>
供给型接口:⽆入参,有返回值。常用于提供数据
方法:T get();
示例:Supplier<Double> randomSupplier = () -> Math.random();
Predicate<T>
断⾔言型接口:有入参,有返回值,返回值类型确定是boolean。常用于过滤操作。
方法:boolean test(T t);
示例:Predicate<String> isLong = s -> s.length() > 5;
2.2 函数式接口应用场景
函数式接口使用场景 函数式接口的使用场景主要包括简化集合操作、异步编程和回调处理、事件监听和处理。
函数式接口,也称为函数接口,是只有一个抽象方法的接口。这种接口设计模式鼓励函数式编程风格,即代码由一系列不可变的函数组成,这些函数可以作为参数传递或返回值。Java 8 引入了 Lambda 表达式和方法引用来支持函数式编程,使得函数式接口的使用更加广泛。
简化集合操作:函数式接口如 Predicate、Function、Consumer 等,可以与 Java 的 Stream API 结合使用,简化对集合的处理逻辑。例如,使用 filter 方法结合 Predicate 接口对集合进行过滤,使用 map 方法结合 Function 接口对集合进行映射,使用 forEach 方法结合 Consumer 接口对集合进行遍历输出。
异步编程和回调处理:在处理异步操作时,函数式接口可以用于定义回调函数,使代码逻辑更清晰。通过 Lambda 表达式和方法引用,可以简洁地表示异步任务的处理逻辑,而无需编写复杂的回调函数。
事件监听和处理:在 GUI 编程或事件驱动系统中,函数式接口可以作为事件处理器,简化事件注册和处理逻辑。通过 Lambda 表达式和方法引用,可以方便地定义事件处理逻辑,而无需编写繁琐的事件监听器类。
此外,函数式接口还可以用于定义自定义操作,如定义一个 GreetingService 接口,其中包含一个 sayMessage 方法,然后使用 Lambda 表达式或方法引用来实现该接口,从而创建自定义的行为。这种灵活性使得函数式接口成为 Java 编程中非常有用的工具。
以下是一个使用函数式接口Predicate和Consumer的简单示例:
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
public class FunctionalInterfaceExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// 使用Predicate过滤长度大于3的名字
Predicate<String> isNameLong = name -> name.length() > 3;
names.stream()
.filter(isNameLong)
.forEach(System.out::println); // 使用Consumer打印过滤后的名字
// 或者自定义Consumer来打印名字
Consumer<String> printer = name -> System.out.println("Name: " + name);
names.stream()
.filter(isNameLong)
.forEach(printer);
}
}
3、接口可以添加默认方法和静态方法,也就是定义不需要实现类实现的方法
以前接口其中一个重要特性是: 其中的方法全都是抽象方法,即都没有方法体
JDK8以后,允许接口中有被default和static修饰的方法带方法体
4、方法引用 −方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
方法引用是一个更加紧凑,易读的 Lambda 表达式,注意方法引用是一个 Lambda 表达式,方法引用操作符是双冒号 "::"。
方法引用有下面几种方式:
对象引用::实例方法名
类名::静态方法名
类名::实例方法名
类名::new (也称为构造方法引用)
类型[]::new (也称为数组引用)
5、重复注解,同一个注解可以使用多次
6、引入Optional来避免空指针
7、Streams API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
8、Date Time API − 加强对日期与时间的处理。
9、新工具 − 新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。
jdeps命令行,来分析类、目录、jar包的类依赖层级关系
10、JVM使用 MetaSpace 代替了永久代(PermGen Space)
11、Nashorn, JavaScript 引擎 − Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。
更多的新特性可以参阅官网:What's New in JDK 8
JDK 11新特性
垃圾收集器增强
Epsilon GC(无操作垃圾收集器,适用于性能测试)
java -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC MyApp
ZGC(低延迟 GC,JDK 11 中为实验性功能,后续版本优化):
java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC MyApp