2006年之后SUN公司决定将JDK进行开源,从此成立了OpenJDK组织进行JDK代码管理。任何人都可以获取该源码,并通过源码构建一个发行版发布到网络上。但是需要一个组织审核来确保构建的发行版是有效的, 这个组织就是JCP(Java Community Process)。2009年,SUN公司被Oracle公司"白嫖"(参考2018年Google赔款),此时大家使用的JDK通常都是Oracle公司的OpenJDK构建版本-OracleJDK。但是,Oracle公司是一个明显只讲商业而不管情怀的公司,接手Java商标之后,明显加快了JDK的发布版本。2018年9月25日,JDK11成功发布,这是一个LTS版本,包含了17个JEP的更新。与此同时,Oracle把JDK11起以往的商业特性全部开源给OpenJDK(例如:ZGC和Flight Recorder)。
根据Oracle的官方说法(Oracle JDK Releases for Java 11 and Later),从JDK11之后,OracleJDK与OpenJDK的功能基本一致。然后,Oracle宣布以后将会同时发行两款JDK:1. 一个是以GPLv2+CE协议下,由Oracle发行OpenJDK(简称为Oracle OpenJDK);2. 另一个是在OTN协议下的传统OracleJDK。这两个JDK共享绝大多数源码,核心差异在于前者可以免费在开发、测试和生产环境下使用,但是只有半年时间的更新支持。后者各个人可以免费使用,但是生产环境中商用就必须付费,可以有三年时间的更新支持。
一、Java平台模块化系统(Jigsaw项目)
Modular development starts with a modular platform. —Alan Bateman 2016.9
--moudule1
---src
----main
-----java
------com.company.package1
------moudule-info.java
---pom.xml
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.jd.jsf.java.util.GregorianCalendar_$$_Template_1798100948_0 (file:/home/export/App/deliveryorder.jd.com/WEB-INF/lib/jsf-1.7.2.jar) to field java.util.Calendar.fields
WARNING: Please consider reporting this to the maintainers of com.jd.jsf.java.util.GregorianCalendar_$$_Template_1798100948_0
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
2.2.1、G1的Full GC从串行改为并行(JEP307)
-Xloggc:/export/Logs/gc.log //输出GC日志到指定文件
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xlog[:option]
option := [][:[][:[][:]]]
'help'
'disable'
what := [,...]
selector := [*][=]
tag-set := [+...]
'all'
tag := name of tag
level := trace
debug
info
warning
error
output := 'stderr'
'stdout'
[file=]
decorators := [,...]
'none'
decorator := time
uptime
timemillis
uptimemillis
timenanos
uptimenanos
pid
tid
level
tags
output-options := [,...]
output-option := filecount=
filesize=
parameter=value
-Xlog:all=warning:stderr:uptime,level,tags
- 默认配置
- 'all' 即是包含所有tag
- 默认日志输出级别warning,位置stderr
- 包含uptime,level,tags三个装饰
-Xlog:safepoint,classhisto*=trace,age*,gc*=info:file=/export/Logs/gc-%t.log:time,tid,level,tags:filecount=5,filesize=50MB
- safepoint表示打印用户线程并发及暂停执行时间
- classhisto表示full gc时打印堆快照信息
- age*,gc* 表示打印包括gc及其细分过程日志,日志级别info,文件:/export/Logs/gc.log。
- 日志格式包含装饰符:time,tids,level,tags
- default output of all messages at level 'warning' to 'stderr'
will still be in effect
- 保存日志个数5个,每个日志50M大小
-Xlog:gc+heap=debug:file=/export/Logs/gc.log:time,tids,level,tags:filecount=5,filesize=1M
- 打印包括gc及其细分过程日志,日志级别info,文件:/export/Logs/gc.log。
- 日志格式包含装饰符:time,tids,level,tags
- default output of all messages at level 'warning' to 'stderr'
will still be in effect
- 保存日志个数5个,每个日志1M大小
JDK9之前的GC日志:
2014-12-10T11:13:09.597+0800: 66955.317: [GC concurrent-root-region-scan-start]
2014-12-10T11:13:09.597+0800: 66955.318: Total time for which application threads were stopped: 0.0655753 seconds
2014-12-10T11:13:09.610+0800: 66955.330: Application time: 0.0127071 seconds
2014-12-10T11:13:09.614+0800: 66955.335: Total time for which application threads were stopped: 0.0043882 seconds
2014-12-10T11:13:09.625+0800: 66955.346: [GC concurrent-root-region-scan-end, 0.0281351 secs]
2014-12-10T11:13:09.625+0800: 66955.346: [GC concurrent-mark-start]
2014-12-10T11:13:09.645+0800: 66955.365: Application time: 0.0306801 seconds
2014-12-10T11:13:09.651+0800: 66955.371: Total time for which application threads were stopped: 0.0061326 seconds
2014-12-10T11:13:10.212+0800: 66955.933: [GC concurrent-mark-end, 0.5871129 secs]
2014-12-10T11:13:10.212+0800: 66955.933: Application time: 0.5613792 seconds
2014-12-10T11:13:10.215+0800: 66955.935: [GC remark 66955.936: [GC ref-proc, 0.0235275 secs], 0.0320865 secs]
JDK9统一日志框架输出的日志格式 :
[2021-02-09T21:12:50.870+0800][258][info][gc] Using G1
[2021-02-09T21:12:51.751+0800][365][info][gc] GC(0) Pause Young (Concurrent Start) (Metadata GC Threshold) 60M->5M(4096M) 7.689ms
[2021-02-09T21:12:51.751+0800][283][info][gc] GC(1) Concurrent Cycle
[2021-02-09T21:12:51.755+0800][365][info][gc] GC(1) Pause Remark 13M->13M(4096M) 0.959ms
[2021-02-09T21:12:51.756+0800][365][info][gc] GC(1) Pause Cleanup 13M->13M(4096M) 0.127ms
[2021-02-09T21:12:51.758+0800][283][info][gc] GC(1) Concurrent Cycle 7.208ms
[2021-02-09T21:12:53.232+0800][365][info][gc] GC(2) Pause Young (Normal) (G1 Evacuation Pause) 197M->15M(4096M) 17.975ms
[2021-02-09T21:12:53.952+0800][365][info][gc] GC(3) Pause Young (Concurrent Start) (GCLocker Initiated GC) 114M->17M(4096M) 15.383ms
[2021-02-09T21:12:53.952+0800][283][info][gc] GC(4) Concurrent Cycle
四、更加优雅的语法或者方法
// 创建只有一个值的可读list,底层不使用数组
static <E> List<E> of(E e1) {
return new ImmutableCollections.List12<>(e1);
}
// 创建有多个值的可读list,底层使用数组
static <E> List<E> of(E e1, E e2, E e3) {
return new ImmutableCollections.List12<>(e1, e2,e3);
}
// 创建单例长度为0的Set结合
static <E> Set<E> of() {
return ImmutableCollections.emptySet();
}
static <E> Set<E> of(E e1) {
return new ImmutableCollections.Set12<>(e1);
}
4.2、接口私有方法
public interface HelloService {
public void sayHello();
// 默认方法
default void saySomething(){
syaEngHello();
sayHello();
};
// 私有方法
private void syaEngHello(){
System.out.println("Hello!");
}
}
4.3、改进的 Stream API
// 循环直到第一个满足条件后停止
default Stream takeWhile(Predicate predicate);
// 循环直到第一个满足条件后开始
default Stream dropWhile(Predicate predicate);
// 根据表达式生成迭代器
static Stream iterate(T seed, Predicate hasNext, UnaryOperator next);
// 使用空值创建空的Stream,避免空指针
static Stream ofNullable(T t);
4.4、JShell
public static void main(String[] args) throws Exception {
var lists = List.of("a", "b", "c");
for (var word : lists) {
System.out.println(word);
}
}
var关键字只能用于可推断类型的代码位置,不能使用于方法形式参数,构造函数形式参数,方法返回类型等。标识符var不是关键字,它是一个保留的类型名称。这意味着var用作变量,方法名或则包名称的代码不会受到影响。但var不能作为类或则接口的名字。
response=urllib.request.urlopen('https://www.python.org') #请求站点获得一个HTTPResponse对象
print(response.read().decode('utf-8')) #返回网页内容
JDK:
HttpURLConnection connection = (HttpURLConnection) new URL("http://localhost:8080/demo/list?name=HTTP").openConnection();
connection.setRequestMethod("GET");
connection.connect();
int responseCode = connection.getResponseCode();
log.info("response code : {}", responseCode);
// read response
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} finally {
connection.disconnect();
}
Apache HttpClient:
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
// 创建Get请求
HttpGet httpGet = new HttpGet("http://localhost:12345/doGetControllerOne");
// 响应模型
CloseableHttpResponse response = null;
// 由客户端执行(发送)Get请求
response = httpClient.execute(httpGet);
// 从响应模型中获取响应实体
HttpEntity responseEntity = response.getEntity();
System.out.println("响应状态为:" + response.getStatusLine());
Java 9 中引入了标准Http Client API 。并在 Java 10 中进行了更新的。到了Java11,在前两个版本中进行孵化的同时,Http Client 几乎被完全重写,并且现在完全支持异步非阻塞。与此同时它是 Java 在 Reactive-Stream 方面的第一个生产实践,其中广泛使用了 Java Flow API。
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://openjdk.java.net/"))
.build();
client.sendAsync(request, BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join();
4.7、Helpful NullPointerExceptions(JEP358)
a.b.c.i = 99;
a[i][j][k] = 99;
在之前,我们只能收到以下异常堆栈信息,然后必须借助DEBUG工具调查问题:
Exception in thread "main" java.lang.NullPointerException
at Prog.main(Prog.java:5)
优化后,我们可以得到更加优雅的空指针异常提示信息:
Exception in thread "main" java.lang.NullPointerException:
Cannot read field "c" because "a.b" is null
at Prog.main(Prog.java:5)
Exception in thread "main" java.lang.NullPointerException:
Cannot load from object array because "a[i][j]" is null
at Prog.main(Prog.java:5)
if (obj instanceof String) {
String s = (String) obj; // grr...
...
}
上面的instanc of语法一共做了三件事:
if (obj instanceof String s) {// obj是否为String类型,如果是创建临时变量s
// Let pattern matching do the work!
...
}
我们可以看到,整体代码风格确实优雅了很多。变量s的作用域为满足条件的判断条件范围之内。因此,以下使用也是合法的:
if (obj instanceof String s && s.length() > 5) {// 因为&&具有短路功能
flag = s.contains("jdk");
}
但是以下用法,则会报错:
if (obj instanceof String s || s.length() > 5) { // Error!
...
}
合理使用,则可以达到以下效果:
// 优化使用前
public final boolean equals(Object o) {
if (!(o instanceof Point))
return false;
Point other = (Point) o;
return x == other.x
&& y == other.y;
}
// 优化使用后:
public final boolean equals(Object o) {
return (o instanceof Point other)
&& x == other.x
&& y == other.y;
}
4.9、更加优雅的Switch用法
// 之前
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);
}
还可以把switch语句当成一个表达式来处理:
T result = switch (arg) {
case L1 -> e1;
case L2 -> e2;
default -> e3;
};
static void howMany(int k) {
System.out.println(
switch (k) {
case 1 -> "one";
case 2 -> "two";
default -> "many";
}
);
}
还可以配合关键字yield,在复杂处理场景里,返回指定值:
int j = switch (day) {
case MONDAY -> 0;
case TUESDAY -> 1;
default -> {
int k = day.toString().length();
int result = f(k);
yield result;
}
};
还有吗?其实在JDK17中,还提出了Swtich 模式匹配的预览功能,可以做到更优雅的条件判断:
// 优化前
static String formatter(Object o) {
String formatted = "unknown";
if (o instanceof Integer i) {
formatted = String.format("int %d", i);
} else if (o instanceof Long l) {
formatted = String.format("long %d", l);
} else if (o instanceof Double d) {
formatted = String.format("double %f", d);
} else if (o instanceof String s) {
formatted = String.format("String %s", s);
}
return formatted;
}
// 优化后
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();
};
}
五、字符串压缩-Compact Strings(JEP254)