1996 年 1 月Sun公司发布第一个正式的Java版本,JDK1.0
1997 年 2 月Sun 公司发布 JDK1.1
1998 年 12 月公司发布 J2SE1.2
1999年,Sun 公司发布了三个版本的 Java,标准版(J2SE,后来改名为 JavaSE)、企业版(J2EE,后来改名为 JavaEE)、微型版(J2ME,后来改名为 JavaME)
2000 年 5 月Sun 公司发布 J2SE1.3
2002 年 2 月Sun 公司发布了在 JCP(Java Community Process) 的标准下开发的J2SE1.4
2004 年 9 月Sun 公司发布 J2SE5
List<Integer> list=new ArrayList<Integer>();
int[] array = {1, 2, 3, 4, 5};
for (int i : array) {
System.out.println(i);
}
enum TestEnum{
one,
two;
TestEnum() {
}
}
//可变参数测试
public static void testVarargs(String... args) {
//本质就是个数组
System.out.println(args[1]);
for (String arg : args) {
System.out.println(arg);
}
}
//单个导入
import static java.lang.Math.PI;
//批量导入
import static java.lang.Math.*;
//注释注解的注解又叫做元注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotations {
//注解内可以添加方法,也可以不添加
//注解方法的返回值只能是基本类型,String,Class类,枚举,注解,可以有默认值。
int id();
String name() default "whh";
Class classType();
TestEnum enumType();
}
2006 年 12 月Sun 公司发布 JavaSE6
2011 年 7 月,Oracle收购Sun 公司,发布 JavaSE7
//二进制字面值前缀0b 或0B
int i = 0b010;//10进制值为2
int j = 0B010;
//数字间的下划线不影响实际值
int k = 1_1;//值为11
Map<String, List<String>> myMap = new HashMap<String, List<String>>(); // 之前
Map<String, List<String>> myMap = new HashMap<>(); // 现在
/*
* 声明在try括号中的对象称为资源,在方法执行完毕后会被自动关闭,相对与之前必须在finally关闭资源,这一特性大大提高了代码的简洁性。
* 所有实现java.lang.AutoCloseable接口的类都作为资源被自动关闭。
*/
try (BufferedReader reader=new BufferedReader(new FileReader("d:1.txt"))){
return reader.readLine();
}
2014 年 3 月,Java SE 8 (LTS)发布
java.util.concurrent.ConcurrentHashMap
类添加了新的方法以支持新的StreamApi和lambada表达式。java.util.concurrent.atomic
包下新增了类以支持可伸缩可更新的变量。java.util.concurrent.ForkJoinPool
类新增了方法以支持 common pool。java.util.concurrent.locks.StampedLock
类,为控制读/写访问提供了一个基于性能的锁,且有三种模式可供选择。2017 年 9 月,Oracle 发布 JavaSE9
JDK 被重新组织成 94 个模块,可以通过新增的 jlink 工具,创建出只包含所依赖的 JDK 模块的自定义运行时镜像,极大地减少 Java 运行时环境的大小。
Java 9 模块的重要特征是在其工件(artifact)的根目录中包含了一个描述模块的 module-info.class 文件。工件的格式可以是传统的 JAR 文件或是 Java 9 新增的 JMOD 文件。
Java 9 允许为 JDK 和应用配置同样的日志实现。新增了 System.LoggerFinder 用来管理 JDK 使 用的日志记录器实现。JVM 在运行时只有一个系统范围的 LoggerFinder 实例。
我们可以通过添加自己的 System.LoggerFinder 实现来让 JDK 和应用使用 SLF4J 等其他日志记录框架。
java.lang.invoke.MethodHandles.Lookup
中的静态工厂方法来创建 VarHandle 对象方法句柄从 Java7 开始引入,Java9 在类java.lang.invoke.MethodHandles 中新增了更多的静态方法来创建不同类型的方法句柄
简化Doclet API。
支持生成HTML5格式。
加入了搜索框,使用这个搜索框可以查询程序元素、标记的单词和文档中的短语。
支持新的模块系统。
增强了Garbage-First(G1)并用它替代Parallel GC成为默认的垃圾收集器。
统一了JVM 日志,为所有组件引入了同一个日志系统。
删除了JDK 8中弃用的GC组合。(DefNew + CMS,ParNew + SerialOld,Incremental CMS)。
$MAJOR.$MINOR.$SECURITY.$PATCH
private instance methods
方法上可以使用@SafeVarargs注解2018 年 3 月,Oracle 发布Java SE 10
//之前的代码格式
URL url = new URL("http://www.oracle.com/");
URLConnection conn = url.openConnection();
Reader reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()))
//java10中用var来声明变量
var url = new URL("http://www.oracle.com/");
var conn = url.openConnection();
var reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
java.util.stream.Collectors
中新增了静态方法,用于将流中的元素收集为不可变的集合G1 是以一种低延时的垃圾回收器来设计的,旨在避免进行 Full GC,但是 Java9 的 G1 的 FullGC 依然是使用单线程去完成标记清除算法,这可能会导致垃圾回收期在无法回收内存的时候触发 Full GC。
为了最大限度地减少 Full GC 造成的应用停顿的影响,从 Java10 开始,G1 的 FullGC 改为并行的标记清除算法,同时会使用与年轻代回收和混合回收相同的并行工作线程数量,从而减少了 Full GC 的发生,以带来更好的性能提升、更大的吞吐量。
在 Java 5 中就已经引入了类数据共享机制 (Class Data Sharing,简称 CDS),允许将一组类预处理为共享归档文件,以便在运行时能够进行内存映射以减少 Java 程序的启动时间,当多个 Java 虚拟机(JVM)共享相同的归档文件时,还可以减少动态内存的占用量,同时减少多个虚拟机在同一个物理或虚拟的机器上运行时的资源占用。
Java 10 在现有的 CDS 功能基础上再次拓展,以允许应用类放置在共享存档中。CDS 特性在原来的 bootstrap 类基础之上,扩展加入了应用类的 CDS (Application Class-Data Sharing) 支持。其原理为:在启动时记录加载类的过程,写入到文本文件中,再次启动时直接读取此启动文本并加载。设想如果应用环境没有大的变化,启动速度就会得到提升。
线程-局部管控:Java 10 中线程管控引入 JVM 安全点的概念,将允许在不运行全局 JVM 安全点的情况下实现线程回调,由线程本身或者 JVM 线程来执行,同时保持线程处于阻塞状态,这种方式使得停止单个线程变成可能,而不是只能启用或停止所有线程
备用存储装置上的堆分配:Java 10 中将使得 JVM 能够使用适用于不同类型的存储机制的堆,在可选内存设备上进行堆内存分配
统一的垃圾回收接口:Java 10 中,hotspot/gc 代码实现方面,引入一个干净的 GC 接口,改进不同 GC 源代码的隔离性,多个 GC 之间共享的实现细节代码应该存在于辅助类中。统一垃圾回收接口的主要原因是:让垃圾回收器(GC)这部分代码更加整洁,便于新人上手开发,便于后续排查相关问题。
2018 年 9 月,发布Java SE 11 (LTS)
//判断字符串是否为空
" ".isBlank();//true
//去除字符串首尾空格
" Java ".strip();// "Java"
//去除字符串首部空格
" Java ".stripLeading(); // "Java "
//去除字符串尾部空格
" Java ".stripTrailing(); // " Java"
//重复字符串多少次
"Java".repeat(3); // "JavaJavaJava"
//返回由行终止符分隔的字符串集合。
"A\nB\nC".lines().count(); // 3
"A\nB\nC".lines().collect(Collectors.toList());
ZGC 即 Z Garbage Collector,是一个可伸缩的、低延迟的垃圾收集器,主要为了满足如下目标进行设计:
ZGC 目前 处在实验阶段,只支持 Linux/x64 平台
Java 11 对 Java 9 中引入并在 Java 10 中进行了更新的 Http Client API 进行了标准化,在前两个版本中进行孵化的同时,Http Client 几乎被完全重写,并且现在完全支持异步非阻塞。
并且,Java11 中,Http Client 的包名由 jdk.incubator.http 改为java.net.http,该 API 通过 CompleteableFuture 提供非阻塞请求和响应语义。
var request = HttpRequest.newBuilder()
.uri(URI.create("https://javastack.cn"))
.GET()
.build();
var client = HttpClient.newHttpClient();
// 同步
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
// 异步
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
从 Java 10 开始,便引入了局部变量类型推断这一关键特性。类型推断允许使用关键字 var作为局部变量的类型而不是实际类型,编译器根据分配给变量的值推断出类型。Java 10 中对 var 关键字存在几个限制:
Java11 开始允许开发者在 Lambda 表达式中使用 var 进行参数声明
2019 年 3 月,发布Java SE 12
传统的 switch 语法存在容易漏写 break 的问题,而且从代码整洁性层面来看,多个 break 本质也是一种重复。
Java12 提供了 swtich 表达式,使用类似 lambda 语法条件匹配成功后的执行块,不需要多写 break。
作为预览特性加入,需要在javac编译和java运行时增加参数–enable-preview。
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
NumberFormat fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
String result = fmt.format(1000);
System.out.println(result); // 输出为 1K,计算工资是多少K更方便了。。。
Redhat 主导开发的 Pauseless GC 实现,主要目标是 99.9% 的暂停小于 10ms,暂停与堆大小无关等
和 Java11 开源的 ZGC 相比(需要升级到 JDK11 才能使用),Shenandoah GC 有稳定的 JDK8u 版本,在 Java8 占据主要市场份额的今天有更大的可落地性
2019 年 9 月,发布Java SE 13
这个关键字 yield是用于返回一个值的。
与return 的区别在于:return 会直接跳出当前循环或者方法,而 yield 只会跳出当前 Switch 块,同时在使用 yield 时,需要有 default 条件
private static String descLanguage(String name) {
return switch (name) {
case "Java": yield "object-oriented, platform independent and secured";
case "Ruby": yield "a programmer's best friend";
default: yield name +" is a good language";
};
}
解决 Java 定义多行字符串时只能通过换行转义或者换行连接符来变通支持的问题,引入三重双引号来定义多行文本
两个"""中间的任何内容都会被解释为字符串的一部分,包括换行符
String json ="{\n" +
" \"name\":\"mkyong\",\n" +
" \"age\":38\n" +
"}\n"; // 未支持文本块之前
String json = """
{
"name":"mkyong",
"age":38
}
""";
为 Socket API 带来了新的底层实现方法,并默认使用新的 Socket 实现,使其易于发现并在排除问题同时增加可维护性
允许在 Java 应用程序执行结束时动态进行类归档,具体能够被归档的类包括:所有已被加载,但不属于默认基层 CDS 的应用程序类和引用类库中的类
2020 年 3 月,发布Java SE 14
/**
* 这个类具有两个特征
* 1. 所有成员属性都是final
* 2. 全部方法由构造方法,和两个成员属性访问器组成(共三个)
* 那么这种类就很适合使用record来声明
*/
final class Rectangle implements Shape {
final double length;
final double width;
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
double length() { return length; }
double width() { return width; }
}
/**
* 1. 使用record声明的类会自动拥有上面类中的三个方法
* 2. 在这基础上还附赠了equals(),hashCode()方法以及toString()方法
* 3. toString方法中包括所有成员属性的字符串表示形式及其名称
*/
record Rectangle(float length, float width) { }
通过 JVM 参数中添加-XX:+ShowCodeDetailsInExceptionMessages,可以在空指针异常中获取更为详细的调用信息,更快的定位和解决问题
a.b.c.i = 99; // 假设这段代码会发生空指针
Exception in thread "main" java.lang.NullPointerException:
Cannot read field 'c' because 'a.b' is null.
at Prog.main(Prog.java:5) // 增加参数后提示的异常中很明确的告知了哪里为空导致
JDK12 引入的 switch(预览特性)在 JDK14 变为正式版本,不需要增加参数来启用,直接在 JDK14 中就能使用
主要是用->来替代以前的:+break;另外就是提供了 yield 来在 block 中返回值
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
System.out.println(6);
break;
case TUESDAY:
System.out.println(7);
break;
case THURSDAY:
case SATURDAY:
System.out.println(8);
break;
case WEDNESDAY:
System.out.println(9);
break;
}
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
可以在判断的是否属于具体的类型同时完成转换
Object obj = "我是字符串";
if(obj instanceof String str){
System.out.println(str);
}