java
java的诞生与历史:
简介:Java是一门面向对象的编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程
java的历史版本更新:
java8的新特性
1、Lambda表达式
Lambda是一个匿名函数, 我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格, 使Java的语言表达能力得到了提升。
(Lambda表达式是对象, 而不是函数, 它们必须依附于一类特别的对象类型:函数式接口)
@Test
public void test() {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("欢迎倾听本次技术分享!");
}
};
r1.run();
Runnable r2=()->System.out.println("欢迎倾听本次技术分享!");
r2.run();
}
2、函数式(Functional) 接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer消费型接口 | T | void | 对象类型为T(任何类型)应用操作,包含的方法:void accept(T t) |
Supplier供给型接口 | 不需要参数 | T | 返回类型为T的对象,包含方法:T get() |
Function<T,R>函数型接口 | T | R | 对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t) |
Predicate断定型接口 | T | boolean | 确定类型为T的对象是否满足约束,并返回boolean值。包含方法: boolean test(T t) |
3. 方法引用与构造器引用
对象 ::实例方法名
类 ::静态方法名
类 ::实例方法名
4. 强大的Stream API
Stream是一种数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据, Stream讲的是计算!
注意:
1、Stream自己不会存储元素。
2、Stream不会改变源对象。相反, 他们会返回一个持有结果的新Stream。(如果最后以collect方法结尾,则会改变原集合的数据,但是集合的地址不会变)
@Test
public void TestDemo09(){
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 23, "male", "New York"));
personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
personList.add(new Person("Anni", 8200, 24, "female", "New York"));
personList.add(new Person("Owen", 9500, 25, "male", "New York"));
personList.add(new Person("Alisa", 7900, 26, "female", "New York"));
personList.stream().map(person -> {
person.setAge(1);
return person;
});
personList.forEach(System.out::println);
System.out.println("==================");
personList.stream().map(person -> {
person.setAge(1);
return person;
}).collect(Collectors.toList());
personList.forEach(System.out::println);
}
输出结果:
Person(name=Tom, salary=8900, age=23, sex=male, area=New York)
Person(name=Jack, salary=7000, age=25, sex=male, area=Washington)
Person(name=Lily, salary=7800, age=21, sex=female, area=Washington)
Person(name=Anni, salary=8200, age=24, sex=female, area=New York)
Person(name=Owen, salary=9500, age=25, sex=male, area=New York)
Person(name=Alisa, salary=7900, age=26, sex=female, area=New York)
==================
Person(name=Tom, salary=8900, age=1, sex=male, area=New York)
Person(name=Jack, salary=7000, age=1, sex=male, area=Washington)
Person(name=Lily, salary=7800, age=1, sex=female, area=Washington)
Person(name=Anni, salary=8200, age=1, sex=female, area=New York)
Person(name=Owen, salary=9500, age=1, sex=male, area=New York)
Person(name=Alisa, salary=7900, age=1, sex=female, area=New York)
(person对象的地址不会变)
3、Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
4、Stream和Collection集合的区别:Collection是一种静态的内存数据结构, 而Stream是有关计算的。前者是主要面向内存, 存储在内存中,后者主要是面向CPU, 通过CPU实现计算。
5. Optional类
为了解决空指针异常, Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染, 它鼓励程序员写更干净的代码。受到Google Guava的启发, Optional类已经成为Java 8类库的一部分。
- 创建Optional类对象的方法:
Optional.of(T t)//创建一个Optional实例, t必须非空;
Optional.empty()//创建一个空的Optional实例;
Optional.ofNullable(T t) //t可以为null;
代码实现
@Test
void testDemo01() {
Optional<String> luoYiMingNotNull = Optional.of("luoyiming");
Optional<String> luoYiMingOfNullable = Optional.ofNullable("luoyiming");
Optional<Object> nullAndNullable = Optional.ofNullable(null);
Optional<Object> empty = Optional.empty();
System.out.println("luoYiMingNotNull :"+luoYiMingNotNull);
System.out.println("luoYiMingOfNullable :"+luoYiMingOfNullable);
System.out.println("nullAndNullable :"+nullAndNullable);
System.out.println("empty :"+empty);
}
- 判断Optional容器中是否包含对象:
boolean isPresent() //判断是否包含对象
void ifPresent(Consumer<? super T> consumer) //如果有值, 就执行Consumer接口的实现代码,并且该值会作为参数传给它
代码实现:
@Test
void testDemo02() {
Optional<String> luoYiMingNotNull = Optional.of("luoyiming");
//luoYiMingNotNull不为空,luoYiMingNotNull.isPresent()为true
if (luoYiMingNotNull.isPresent()) {
System.out.println("luoYiMingNotNull :不是空值");
}
luoYiMingNotNull.ifPresent(System.out::println);
Optional<Object> nullAndNullable = Optional.ofNullable(null);
//nullAndNullable为空nullAndNullable.isPresent()为false
if (!nullAndNullable.isPresent()) {
System.out.println("nullAndNullable :是空值");
}
nullAndNullable.ifPresent(opt -> {
System.out.println("nullAndNullable :是空值");
});
}
-
获取Optional容器的对象
T get() //如果调用对象包含值, 返回该值, 否则抛异常 T orElse(T other) //如果有值则将其返回, 否则返回指定的other对象。 T orElseGet(Supplier<? extends T> other) //如果有值则将其返回, 否则返回由Supplier接口实现提供的对象。 T orElseThrow(Supplier<? extends X> exceptionSupplier) //如果有值则将其返回, 否则抛出由Supplier接口实现提供的异常。
@Test void testDemo10() { //调用工厂方法创建Optional实例 Optional<String> name = Optional.of("Sanaulla"); //传入参数为null,抛出NullPointerException. Optional<String> someNull = Optional.ofNullable(null); //isPresent方法用来检查Optional实例中是否包含值 if (name.isPresent()) { //在Optional实例内调用get()返回已存在的值 System.out.println(name.get());//输出Sanaulla } //如果值不为null,orElse方法返回Optional实例的值。 //如果为null,返回传入的消息。 //输出: There is no value present! System.out.println(someNull.orElse("There is no value present!")); //输出: Sanaulla System.out.println(name.orElse("There is some value!")); System.out.println("============================="); //orElseGet与orElse方法类似,区别在于orElse传入的是默认值, //orElseGet可以接受一个lambda表达式生成默认值。 //输出: Default Value System.out.println(someNull.orElseGet(() -> "Default Value")); //输出: Sanaulla System.out.println(name.orElseGet(() -> "Default Value")); }
6.接口增强
为了提高接口的可拓展性,
新增 : 默认方法 default 关键字修饰
1.1 default 关键字修饰方法,必须有方法体
1.2 实现类可以重写该方法
1.3 调用方式 : 通过实现类的对象进行调用
新增 :静态方法
2.1 static 关键字修饰方法,必须有方法体
2.2 实现类不可以重写该方法
2.3 调用方式 : 只能通过 【接口名.静态方法名】 进行调用
7.重复注解与类型注解
注解就相当于一种标记,在程序中加了注解就等于为程序加了某种标记。
@Retention
:
-
RetentionPolicy.SOURCE
-
RetentionPolicy.CLASS(默认)
-
RetentionPolicy.RUNTIME
java源文件–> class文件 --> 内存中的字节码
@Target
-
ElementType.ANNOTATION_TYPE(注解)
-
ElementType.CONSTRUCTOR(构造方法)
-
ElementType.FIEID(成员变量)
-
ElementType.LOCAL_VARIABLE(变量)
-
ElementType.METHOD(方法)
-
ElementType.PACKAGE(包)
-
ElementType.PARAMETER(参数)
-
ElementType.TYPE。
-
TYPE_PARAMETER:表示该注解能写在类型参数的声明语句中。 类型参数声明如: 、
-
TYPE_USE:表示注解可以再任何用到类型的地方使用,比如允许在如下位置使用:
- 创建对象(用new关键字创建)
- 类型转换
- 使用implements实现接口
- 使用throws声明抛出异常
Java 8 引入了重复注解机制,这样相同的注解可以在同一地方使用多次。重复注解机制本身必须用 @Repeatable 注解。
public class RepeatingAnnotations {
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Filters {
Filter[] value();
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Filters.class)
public @interface Filter {
String value();
}
@Filter("filter1")
@Filter("filter2")
public interface Filterable1 {
}
@Filters({@Filter("filter1"),
@Filter("filter2")})
public interface Filterable2 {
}
@Test
public void annotationTest_new() {
for (Filter filter : Filterable1.class.getAnnotationsByType(Filter.class)) {
System.out.println(filter.value());
}
}
@Test
public void annotationTest_old() {
for (Filter filter : Filterable2.class.getAnnotationsByType(Filter.class)) {
System.out.println(filter.value());
}
}
Java9新特性
1 .模块化系统
模块(module)的概念,其实就是package外再裹一层,也就是说,用模块来管理各个package,通过声明某个package暴露,不声明默认就是隐藏。因此,模块化使得代码组织上更安全,因为它可以指定哪些部分可以暴露,哪些部分隐藏。
导出模块
被引用模块需要导出指定的文件夹,并且在根目录下定义 module-info.java 文件,编写需要导出的文件包全路径名。
module modulea {
exports com.lz.java9.bean2;
exports com.lz.java9.bean;
}
引用模块
在引用项目的根目录下新建一个 module-info.java 文件,如果不新建module-info文件,模块化不生效,可以调用包中的所有类,编写需要引入的模块名称。
module moduleb {
requires modulea;
}
2.jshell
JShell的目标是提供一个交互工具,通过它来运行和计算java中的表达式。开发者可以轻松地与JShell交互,其中包括:编辑历史,tab键代码补全,自动添加分号,可配置的imports和definitions。其他的很多主流编程语言如python都已经提供了console,便于编写一些简单的代码用于测试。
demo
jshell> for(int i=0; i<10; i++){
...> System.out.println(i);
...> }
输出:
0
1
2
3
4
5
6
7
8
9
3.多版本兼容jar包
多版本兼容 JAR 功能能让你创建仅在特定版本的 Java 环境中运行库程序时选择使用的 class 版本。通过 --release 参数指定编译版本。具体的变化就是 META-INF 目录下 MANIFEST.MF 文件新增了一个属性:
Multi-Release: true
然后 META-INF 目录下还新增了一个 versions 目录,如果是要支持 java9,则在 versions 目录下有 9 的目录。
multirelease.jar
├── META-INF
│ └── versions
│ └── 9
│ └── multirelease
│ └── Helper.class
├── multirelease
├── Helper.class
└── Main.class
实例
使用多版本兼容 JAR 功能将 Tester.java 文件生成了两个版本的 jar 包, 一个是 jdk 7,另一个是 jdk 9,然后我们再不同环境下执行。
java8
public class Tester {
public static void main(String[] args) {
System.out.println("Inside java 8");
}
}
java9
public class Tester {
public static void main(String[] args) {
System.out.println("Inside java 9");
}
}
编译两个文件
javac --release 9 Tester.java
javac --release 8 Tester.java
创建多版本兼容 jar 包
jar -c -f test.jar -C java7 . --release 9 -C java9.
在不同的jdk环境下执行打印不同的结果
4.接口中声明私有方法
5.钻石操作符使用升级
6.异常处理try-with-resources改进
java9之前
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
public class Tester {
public static void main(String[] args) throws IOException {
System.out.println(readData("test"));
}
static String readData(String message) throws IOException {
Reader inputString = new StringReader(message);
BufferedReader br = new BufferedReader(inputString);
try (BufferedReader br1 = br) {
return br1.readLine();
}
}
}
java9之后
在 Java 9 中,我们不需要声明资源 br1 就可以使用它,并得到相同的结果。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
public class Tester {
public static void main(String[] args) throws IOException {
System.out.println(readData("test"));
}
static String readData(String message) throws IOException {
Reader inputString = new StringReader(message);
BufferedReader br = new BufferedReader(inputString);
try (br) {
return br.readLine();
}
}
}
7._ 下划线命名标识符不能单独使用
8.String 底层存储结构发生变化使用字节数组
创建不可变集合
List<String> list = List.of("1", "2", "q");
Set<String> set = Set.of("aa", "bb", "cc", "dd");
Map<String, Integer> map = Map.of("aa", 1, "bb", 2);
9 增强Stream API
takeWhile 从Stream中依次获取满足条件的元素,直匹配到一个不满足条件为止结束获取,不同与filter
List<Integer> list = List.of(11,33,44,102,232,454,67,556,46,78);
list.stream().takeWhile(x -> x < 100).forEach(System.out::println);
// 输出结果如下
11
33
44
dropWhile 从Stream中依次删除满足条件的元素,直到匹配到一个不满足条件为止结束删除
List<Integer> list = List.of(11,33,44,102,232,454,67,556,46,78);
list.stream().dropWhile(x -> x < 100).forEach(System.out::println);
// 输出结果如下
102
232
454
67
556
46
78
Stream.ofNullable(null) 允许单一的null元素
Stream.iterate重载方法
Stream.iterate(0, k -> k + 1).limit(12).forEach(System.out::println);
// 9 新增的重载方法
Stream.iterate(0, k -> k < 12, k -> k + 1).forEach(System.out::println);
10.Optional新增元素转化为stream()方法等
Optional.of(List.of(1, 23, 4, 5, 6)).stream().forEach(System.out::println);
11.多分辨率图像API
12.全新的HTTP客户端API(Java11才正式可用进行了修改和包名改变)
HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest httpRequest = HttpRequest
.newBuilder(new URI("https://www.baidu.com"))
.GET()
.build();
HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
13.InputStream 增加transferTo方法,将数据直接传输到输出流中
14.统一的JVM日志
Java10新特性
1、局部变量的类型推断 var关键字
var list = new ArrayList<String>();
list.add("hello,world!");
System.out.println(list);
2、GC改进和内存管理 并行全垃圾回收器 G1
3、新增API:ByteArrayOutputStream
4、新增API:List、Map、Set
5、新增API:java.util.Properties
6、新增API: Collectors收集器
7、Optional 新增orElseThrow方法
8、基于Java的实验性JIT编译器
9.Java 10 开启了 Java JIT编译器 Graal,用作Linux / x64平台上的实验性JIT编译器。
Java11新特性
1、字符串新增方法
String str = " qq eeee ";
System.out.println(str.isBlank());// 是否为空
System.out.println(str.strip());// 去除开头结尾空格
System.out.println(str.stripLeading());// 去除头部空格
System.out.println(str.stripTrailing());// 去除尾部空格
System.out.println(str.repeat(3));// 复制三次
System.out.println(str.lines().count());// 行数操作统计
2、Optional isEmpty方法
3、局部变量类型推断升级
Consumer<String> con = (@Deprecated var c) -> System.out.println(c.toLowerCase());
4、确认HttpClient使用,标准化并修改优化
5、java命令直接运行源文件,不需要事先javac编译
6、引入实验性的 ZGC
Java12新特性
1、更简洁的 switch 语法(预览功能)
在之前的 JAVA 版本中,switch 语法还是比较啰嗦的,如果多个值走一个逻辑需要写多个 case:
DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
String typeOfDay = "";
switch (dayOfWeek) {
case MONDAY:
case TUESDAY:
case WEDNESDAY:
case THURSDAY:
case FRIDAY:
typeOfDay = "Working Day";
break;
case SATURDAY:
case SUNDAY:
typeOfDay = "Day Off";
}
Java12
typeOfDay = switch (dayOfWeek) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Working Day";
case SATURDAY, SUNDAY -> "Day Off";
};
//特定场景的计算逻辑
int day = 1;
int result = switch (day) {
case 1, 2, 3, 4, 5 -> 1;
case 6, 7 -> 2;
default -> 0;
};
System.out.println(result);
2、核心库java.lang中支持Unicode11
1、684个新角色
1.1、66个表情符号字符
1.2、Copyleft符号
1.3、评级系统的半星
1.4、额外的占星符号
1.5、象棋中国象棋符号
2、11个新区块
2.1、格鲁吉亚扩展
2.2、玛雅数字
2.3、印度Siyaq数字
2.4、国际象棋符号
3、7个新脚本
3.1、Hanifi Rohingya
3.2、Old Sogdian
3.3、Sogdian
3.4、Dogra
3.5、Gunjala Gondi
3.6、Makasar
3.7、Medefaidrin
4、核心库java.text支持压缩数字格式
System.out.println(NumberFormat.getCompactNumberInstance().format(10000000));
// 输出结果:1000万
4、Collectors.teeing 新增方法
Collectors.teeing: 将 downstream1 和 downstream2 的流入合并,然后从 merger 流出
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class SwitchDemo {
public static void main(String[] args) {
CountSum countsum = Stream.of(2, 11, 1, 5, 7, 8, 12)
.collect(Collectors.teeing(
Collectors.counting(),
Collectors.summingInt(e -> e),
CountSum::new));
System.out.println(countsum.toString());
}
}
class CountSum {
private final Long count;
private final Integer sum;
public CountSum(Long count, Integer sum) {
this.count = count;
this.sum = sum;
}
@Override
public String toString() {
return "CountSum{" +
"count=" + count +
", sum=" + sum +
'}';
}
}
5、安全库javax.net.ssl
ChaCha20和Poly1305 TLS密码
JSSE中添加了使用ChaCha20-Poly1305算法的新TLS密码套件。默认情况下启用这些密码套件。TLS_CHACHA20_POLY1305_SHA256密码套件适用于TLS 1.3。
6、移除项
核心库/ java.util.jar中,删除java.util.ZipFile / Inflator / Deflator中的finalize方法
核心库/ java.util.jar中,删除java.util.ZipFile / Inflator / Deflator中的finalize方法
工具/ javac的删除javac支持6 / 1.6源,目标和发布值
7、JVM常量API
引入API来模拟关键类文件和运行时工件的名义描述,特别是可从常量池加载的常量。
在新的 java.lang.invoke.constant 包中定义了一系列基于值的符号引用(JVMS 5.1)类型,它们能够描述每种可加载常量。
符号引用以纯 nominal 形式描述可加载常量,与类加载或可访问性上下文区分开。有些类可以作为自己的符号引用(例如 String),而对于可链接常量,定义了一系列符号引用类型(ClassDesc、MethodTypeDesc、MethodHandleDesc 和 DynamicConstantDesc),它们包含描述这些常量的 nominal 信息。
8、只保留一个 AArch64 实现(源码)
在保留 32 位 ARM 实现和 64 位 aarch64 实现的同时,删除与 arm64 实现相关的所有源码。
JDK 中存在两套 64 位 ARM 实现,主要存在于 src/hotspot/cpu/arm 和 open/src/hotspot/cpu/aarch64 目录。两者都实现了 aarch64,现在将只保留后者,删除由 Oracle 提供的 arm64。这将使贡献者将他们的精力集中在单个 64 位 ARM 实现上,并消除维护两套实现所需的重复工作。
9、默认CDS档案
针对 64 位平台,使用默认类列表增强 JDK 构建过程,以生成类数据共享(class data-sharing,CDS)归档。
10、G1的可流动混合收集
如果G1混合集合可能超过暂停目标,则使其可以中止。
11、G1 及时返回未使用的已分配内存
增强 G1 GC,以便在空闲时自动将 Java 堆内存返回给操作系统。
为了实现向操作系统返回最大内存量的目标,G1 将在应用程序不活动期间定期执行或触发并发周期以确定整体 Java 堆使用情况。这将导致它自动将 Java 堆的未使用部分返回给操作系统。而在用户控制下,可以可选地执行完整的 GC,以使返回的内存量最大化。
12、JDK12之Shenandoah低暂停时间垃圾收集器(实验性)
添加一个名为Shenandoah的新垃圾收集(GC)算法,通过与正在运行的Java线程同时进行疏散工作来减少GC暂停时间。使用Shenandoah的暂停时间与堆大小无关, 这意味着无论堆是200MB还是200GB,您都将具有相同的一致暂停时Shenandoah是适用于评估响应性和可预测的短暂停顿 的应用程序的算法。目标不是解决所有JVM暂停问题。由于GC之外的其他原因(例如安全时间点(TTSP)发布或监控通胀)而暂停时间超出了此JEP的范围。
13、JDK12之Microbenchmark Suite
在JDK源代码中添加一套基本的微基准测试,使开发人员可以轻松运行现有的微基准测试并创建新的基准测试。
Java13新特性
1、switch 语法再增强
JAVA 12 中虽然增强了 swtich 语法,但并不能在 -> 之后写复杂的逻辑,JAVA 12 带来了 swtich更完美的体验,就像 lambda一样,可以写逻辑,然后再返回
typeOfDay = switch (dayOfWeek) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> {
// do sth...
yield "Working Day";
}
case SATURDAY, SUNDAY -> "Day Off";
};
2、多行文本块(预览)
java13之前
String html = "<html>\n" +
" <body>\n" +
" <p>Hello, world</p>\n" +
" </body>\n" +
"</html>\n";
java13
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
3、重新实现传统套接字API
使用更简单,更现代的实现替换java.net.Socket和java.net.ServerSocketAPI使用的底层实现,
易于维护和调试。
新的实现旨在易于适应使用用户模式线程(也称为光纤),这些线程正在Project Loom中进行探索。上述传统API可以追溯到JDK 1.0,并且包含传统C和Java代码的混合,这些代码被描述为调试和维护的痛苦。遗留实现还存在其他问题:支持异步关闭,导致可靠性和移植问题的本机数据结构,以及需要彻底检查的并发问题。
4、API增加新方法
FileSystems.newFileSystem新方法
核心库/ java.nio中添加了FileSystems.newFileSystem(Path,Map <String,?>)方法,添加了三种新方法java.nio.file.FileSystems,以便更轻松地使用将文件内容视为文件系统的文件系统提供程序。
nio新方法
核心库/ java.nio中新的java.nio.ByteBuffer批量获取/放置方法转移字节而不考虑缓冲区位置。
核心库/ java.util中:I18N
支持Unicode 12.1,此版本将Unicode支持升级到12.1,其中包括以下内容:
java.lang.Character支持12.1级的Unicode字符数据库,其中12.0从11.0开始增加554个字符,
总共137,928个字符。这些新增内容包括4个新脚本,总共150个脚本,以及61个新的表情符号字符。
U+32FF SQUARE ERA NAME REIWA从12.0开始,12.1只添加一个字符。java.text.Bidi和
java.text.Normalizer类分别支持12.0级的Unicode标准附件,#9和#15。
java.util.regexpackage支持基于12.0级Unicode标准附件#29的扩展字形集群。
5、增强ZGC
增强ZGC以将未使用的堆内存返回给操作系统。
ZGC目前没有取消提交并将内存返回给操作系统,即使该内存长时间未使用。对于所有类型的应用
程序和环境,此行为并非最佳,尤其是那些需要关注内存占用的应用程序和环境 例如:通过使用支付资
源的容器环境。应用程序可能长时间处于空闲状态并与许多其他应用程序共享或竞争资源的环境。应用
程序在执行期间可能具有非常不同的堆空间要求。
例如,启动期间所需的堆可能大于稳态执行期间稍后所需的堆。HotSpot中的其他垃圾收集器,如
G1和Shenandoah,提供了这种功能,某些类别的用户发现它非常有用。将此功能添加到ZGC将受到同一
组用户的欢迎。
Java14新特性
1、Switch(最终版)
和之前的jdk12、13功能一样,只不过确定下来为最终版
2、Record(预览功能)
使用它可以替代构造器、equal方法、toString方法,hashCode方法
public record Point(int x, int y) {
}
public static void main(String[] args) {
System.out.println(new Point(1,2));
}
由于用record声明的类,已经继承了java.lang.Record 故,record 不能在显示的继承其它类。
为了对record 的支持,java.lang.Class引入了*isRecord( )和getRecordComponents( )方法。其中isRecord( )*为判断一个类是否用record进行声明的,*getRecordComponents( )*获取record 中的属性数组RecordComponent[ ]。该数组中包含属性的类型,和属性的值。
3、instanceof的模式匹配(预览版)
Object o = new String("test");
if (o instanceof String str) {
System.out.println(str);
} else{
// System.out.println(str); 报错
}
4、NullPointerExceptions 错误栈
Java14之前,NEP报错信息不会指出为Null的实例具体是那一个。例如:a.b.c.d 出现NEP时,开发者无法确定究竟是a、b、c、d中的那个变量报了空指针。而在这个新特点的加入之后,NEP错误栈则会明确表明,触发NEP的对象是哪个。
public static void main(String[] args) {
A a = new A();
a.b.toString();
}
static class A {
B b;
}
static class B {
}
// 运行结果明确指出 a.b 是null
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Object.toString()" because "a.b" is null
at com.lz.java12.Test.main(Test.java:6)
// 改动再次运行
A a = null;
a.b.toString();
// 明确指出 a 是 null
Exception in thread "main" java.lang.NullPointerException: Cannot read field "b" because "a" is null
at com.lz.java12.Test.main(Test.java:6)
5、打包工具 (Incubator)
jpackage打包工具可以将Java应用程序打包为针对特定平台的安装包,这个安装包包含所有必需的依赖项。该应用程序可以以普通JAR文件集合或模块集合的方式提供。软件包格式可以分为:
Linux:deb和rpm
macOS:pkg和dmg
Windows:msi和exe
6、垃圾回收器(更新优化)
移除 CMS(Concurrent Mark Sweep)垃圾收集器
ZGC优化window和mac
弃用 ParallelScavenge + SerialOld GC 组合
7、外部存储器访问 API(孵化)
目的是引入一个 API,以允许 Java 程序安全、有效地访问 Java 堆之外的外部存储器。如本机、持久和托管堆。
Java15新特性
1、Edwards-Curve 数字签名算法
Java15引入了Edwards-Curve(EdDSA)数据签名算法,EdDAS具有更好的性能和更高的安全性。
// example: generate a key pair and sign
KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519");
KeyPair kp = kpg.generateKeyPair();
// algorithm is pure Ed25519
Signature sig = Signature.getInstance("Ed25519");
sig.initSign(kp.getPrivate());
sig.update(msg);
byte[] s = sig.sign();
// example: use KeyFactory to contruct a public key
KeyFactory kf = KeyFactory.getInstance("EdDSA");
boolean xOdd = ...
BigInteger y = ...
NamedParameterSpec paramSpec = new NamedParameterSpec("Ed25519");
EdECPublicKeySpec pubSpec = new EdECPublicKeySpec(paramSpec, new EdPoint(xOdd, y));
PublicKey pubKey = kf.generatePublic(pubSpec);
2、封闭类(预览)
封闭类和接口主要限制能被哪些类扩展或实现,增加开发人员对定义的类或接口进行管控,实现该类需要得到定义者允许。
密闭类修饰符 sealed
指定可扩展修饰符 permits
public abstract sealed class Shape
permits Circle, Rectangle, Square {...}
密闭类 Shape,定义了三个允许的子类。
预览版作为了解,更多特性见:JEP 360: Sealed Classes (Preview) (java.net)
3、隐藏类
标准 API 来定义无法发现且具有有限生命周期的隐藏类,从而提高 JVM 上所有语言的效率。JDK内部和外部的框架将能够动态生成类,而这些类可以定义隐藏类。通常来说基于JVM的很多语言都有动态生成类的机制,这样可以提高语言的灵活性和效率。
隐藏类天生为框架设计的,在运行时生成内部的class。
隐藏类只能通过反射访问,不能直接被其他类的字节码访问。
隐藏类可以独立于其他类加载、卸载,这可以减少框架的内存占用。
不能直接被其他class的二进制代码使用的class。隐藏类主要被一些框架用来生成运行时类,但是这些类不是被用来直接使用的,而是通过反射机制来调用。
比如在JDK8中引入的lambda表达式,JVM并不会在编译的时候将lambda表达式转换成为专门的类,而是在运行时将相应的字节码动态生成相应的类对象。
java.lang.reflect.Proxy可以定义隐藏类作为实现代理接口的代理类。
java.lang.invoke.StringConcatFactory可以生成隐藏类来保存常量连接方法;
java.lang.invoke.LambdaMetaFactory可以生成隐藏的nestmate类,以容纳访问封闭变量的lambda主体;
3、禁用、弃用偏向锁
4、文本块(正式版)
自Java13引入了文本块 解决多行的问题,Java14 优化 增加\和\s的符号区分 在Java15中 对文本框改进如下
stripIndent()用于从文本块去除空白字符
translateEscapes() 用于翻译转义字符
formatted()用于格式化
5、ZGC正式
ZGC是Java 11引入的新的垃圾收集器(JDK9以后默认的垃圾回收器是G1),经过了多个实验阶段,自此终于成为正式特性。
自 2018 年以来,ZGC 已增加了许多改进,从并发类卸载、取消使用未使用的内存、对类数据共享的支持到改进的 NUMA 感知。此外,最大堆大小从 4 TB 增加到 16 TB。支持的平台包括 Linux、Windows 和 MacOS。
ZGC是一个重新设计的并发的垃圾回收器,通过减少 GC 停顿时间来提高性能。
默认的GC仍然还是G1;之前需要通过-XX:+UnlockExperimentalVMOptions -XX:+UseZGC来启用ZGC,现在只需要-XX:+UseZGC就可以。
6、Shenandoah GC正式
一种低停顿的垃圾回收器,-XX:+UseShenandoahGC 开启 不需要添加参数 -XX:+UnlockExperimentalVMOptions
7、外部存储器访问 API(二次孵化)
Foreign-Memory Access API在JDK14被作为incubating API引入,在JDK15处于Second Incubator,提供了改进。
8、重新实现 DatagramSocket API
JEP 373:Reimplement the Legacy DatagramSocket API(重新实现 DatagramSocket API)
新的计划是JEP 353的后续,该方案重新实现了遗留的套接字API。
更改java.net.DatagramSocket 和 java.net.MulticastSocket 为更加简单、现代化的底层实现。提高了 JDK 的可维护性和稳定性。
通过将java.net.datagram.Socket和java.net.MulticastSocket API的底层实现替换为更简单、更现代的实现来重新实现遗留的DatagramSocket API。
9、移除废弃
1、移除Solaris 和 SPARC 端口
删除对Solaris/SPARC、Solaris/x64和Linux/SPARC端口的源代码和构建支持,在JDK 14中被标记为废弃,在JDK15版本正式移除。
2、移除the Nashorn JS引擎
Nashorn是在JDK提出的脚本执行引擎,该功能是 2014 年 3 月发布的 JDK 8 的新特性。在JDK11就已经把它标记为废弃了,JDK15完全移除。
在JDK11中取以代之的是GraalVM。GraalVM是一个运行时平台,它支持Java和其他基于Java字节码的语言,但也支持其他语言,如JavaScript,Ruby,Python或LLVM。性能是Nashorn的2倍以上。
JDK15移除了Nashorn JavaScript Engine及jjs 命令行工具。具体就是jdk.scripting.nashorn及jdk.scripting.nashorn.shell这两个模块被移除了。
Java16新特性
1、JEP 338: Vector API (孵化阶段)
提供了jdk.incubator.vector来用于矢量计算,实例如下
static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_256;
void vectorComputation(float[] a, float[] b, float[] c) {
for (int i = 0; i < a.length; i += SPECIES.length()) {
var m = SPECIES.indexInRange(i, a.length);
// FloatVector va, vb, vc;
var va = FloatVector.fromArray(SPECIES, a, i, m);
var vb = FloatVector.fromArray(SPECIES, b, i, m);
var vc = va.mul(va).
add(vb.mul(vb)).
neg();
vc.intoArray(c, i, m);
}
)
2、JEP 389: Foreign Linker API (孵化阶段)
提供jdk.incubator.foreign来简化native code的调用。
易用: 用一个纯Java开发模型替换JNI.
支持C语言:
通用性:
高性能:
3、instanceof模式匹配、Record、jpackage打包工具开始正式使用
instanceof的模式匹配在JDK14作为preview,在JDK15作为第二轮的preview,在JDK16转正
Record类型在JDK14作为preview,在JDK15处于第二轮preview,在JDK16转正
jpackage在JDK14引入,JDK15作为incubating工具,在JDK16转正,从jdk.incubator.jpackage转为jdk.jpackage。它支持Linux: deb and rpm、macOS: pkg and dmg、Windows: msi and exe
4、ZGC优化
实现了并发thread-stack处理来降低GC safepoints的负担
5、Elastic Metaspace
及时地将未使用的 HotSpot 类元数据(即元空间)内存返回给操作系统,减少元空间占用,并简化元空间代码以降低维护成本。
Java17新特性
1、Sealed 密封类转正
sealed class 密封类允许描述哪个类或接口可以扩展或实现这个类或接口。简而言之,我们可以限制谁可以使用这个类或接口。
2、提供更好的伪随机数生成
为伪随机数生成器 (PRNG) 提供新的接口类型和实现,包括可跳转 PRNG 和另一类可拆分 PRNG 算法 (LXM)。
引入了一个名为RandomGenerator的新接口。该接口的目标是为所有现有和新的PRNG提供统一的API。
RandomGenerator提供名为ints、longs、doubles、nextBoolean、nextInt、nextLong、nextDouble和nextFloat的方法。
3、Switch模式匹配(预览)
通过对 switch 表达式和语句的模式匹配以及对模式语言的扩展来增强 Java 编程语言。将模式匹配扩展到 switch 允许针对多个模式测试表达式,每个模式都有特定的操作,因此可以简洁安全地表达复杂的面向数据的查询。这是 JDK 17 中的预览语言功能。
static String formatterPatternSwitch(Object o) {
return switch (o) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> o.toString();
};
}
4、用于特定于上下文的反序列化过滤器
5、浮点运算更加严格
简化数字敏感库开发,包括java.lang.Math和java.lang.StrictMath
6、删除一些功能
7、删除实验性 AOT 和 JIT 编译器
8、删除Applet API
9、弃用安全管理器Security Manager
弃用安全管理器以便在将来的版本中删除。安全管理器可追溯到 Java 1.0。多年来,它一直不是保护客户端 Java 代码的主要方法,也很少用于保护服务器端代码。为了推动 Java 向前发展,我们打算弃用安全管理器,以便与旧版 Applet API (JEP 398) 一起删除。
10、移除RMI激活机制
删除远程方法调用 (RMI) 激活机制,同时保留 RMI 的其余部分。
参考:
Java9、10、11、12、13、14、15、16、17个版本新特性 作者:small_to_large
https://blog.csdn.net/small_to_large/article/details/124239135?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-3-124239135-blog-120437852.t5_landing_title_tags_v2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-3-124239135-blog-120437852.t5_landing_title_tags_v2&utm_relevant_index=6
java各版本的新特性 作者:codingdong
https://blog.csdn.net/ahutdbx/article/details/120437852