jdk新特性
背景和发展趋势
按照 Oracle 公布的支持路线图,Java 11将会获得Oracle提供的长期支持服务,直至2026年9月。
按照官方的说法,新的发布周期会严格遵循时间点,将于每年的3月份和9月份发布。
新的长期支持版本每三年发布一次,根据后续的发布计划,下一个长期支持版Java 17 将于2021年发布。
从JDK11开始,OpenJDK与OracleJDK基本完全一样。但是它们之间仍然有一些差异.
发布模式
新模式下的 Java 版本发布都会包含许多变更,包括语言变更和 JVM 变更,这两者都会对 IDE、字节码库和框架产生重大影响。此外,不仅会新增其他 API,还会有 API 被删除(这在 Java 8 之前没有发生过)。
oracleJDK要收费?
Oracle jdk 具体分个人版本和商业版本两种
商业版本在19年1月停止免费的更新,这之前的更新还是能够免费用,交钱可以继续获得后续的更新
个人版本在20年12月停止免费的更新,这之前的更新还是能够免费用,交钱可以继续获得后续的更新
而Openjdk 在持续更新前都是免费的,而且据悉Openjdk和Oracle jdk基本没什么区别。
java8,java9, java 10, java11 新特性
java8:
新特性
Lambda表达式与函数式接口
- lambda表达式
引入了一个新的操作符 "->" 该操作符称为箭头操作符或 Lambda 操作符,箭头操作符将 Lambda 表达式拆分成两部分:
左侧:指定了 Lambda 表达式需要的所有参数
右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能。
在最简单的形式中,一个lambda可以由用逗号分隔的参数列表、–>符号与函数体三部分表示。例如:
Arrays.asList("a", "b", "d").forEach(e -> System.out.println(e));
/*
语法格式一:无参数,无返回值
* () -> System.out.println("Hello Lambda!");
*
* 语法格式二:有一个参数,并且无返回值
* (x) -> System.out.println(x)
*
* 语法格式三:若只有一个参数,小括号可以省略不写
* x -> System.out.println(x)
*
* 语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
* Comparator<Integer> com = (x, y) -> {
* System.out.println("函数式接口");
* return Integer.compare(x, y);
* };
*
* 语法格式五:若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写
* Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
*
* 语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
* (Integer x, Integer y) -> Integer.compare(x, y);
*/
@Test
public void test3(){
//有一个参数,并且无返回值
Consumer<String> con = x -> System.out.println(x);
con.accept("hello!");
//有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
Comparator<Integer> com = (x, y) -> {
System.out.println("hello!");
return Integer.compare(x, y);
};
//若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写
Comparator<Integer> com2 = (x, y) -> Integer.compare(x, y);
}
但是,Lambda 表达式需要“函数式接口”的支持
- 函数式接口
java8内置四大核心函数式接口
函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。 可以使用注解 @FunctionalInterface 修饰
/*
* Java8 内置的四大核心函数式接口
*/
//Consumer<T> 消费型接口 :
@Test
public void test1(){
happy(1000, (m) -> System.out.println("韩寒喜欢吃火锅,每次消费:" + m + "元"));
}
public void happy(double money, Consumer<Double> con){
con.accept(money);
}
//Supplier<T> 供给型接口 :
@Test
public void test2(){
List<Integer> numList = getNumList(10, () -> (int)(Math.random() * 100));
for (Integer num : numList) {
System.out.println(num);
}
}
//需求:产生指定个数的整数,并放入集合中
public List<Integer> getNumList(int num, Supplier<Integer> sup){
List<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
Integer n = sup.get();
list.add(n);
}
return list;
}
//Function<T, R> 函数型接口:
@Test
public void test3(){
String newStr = strHandler("\t\t\t 啷里格啷 ", (str) -> str.trim());
System.out.println(newStr);
String subStr = strHandler("朗格里格朗", (str) -> str.substring(2, 5));
System.out.println(subStr);
}
//需求:用于处理字符串
public String strHandler(String str, Function<String, String> fun){
return fun.apply(str);
}
//Predicate<T> 断言型接口:
@Test
public void test4(){
List<String> list = Arrays.asList("Hello", "atguigu", "Lambda", "www", "ok");
List<String> strList = filterStr(list, (s) -> s.length() > 3);
for (String str : strList) {
System.out.println(str);
}
}
//需求:将满足条件的字符串,放入集合中
public List<String> filterStr(List<String> list, Predicate<String> pre){
List<String> strList = new ArrayList<>();
for (String str : list) {
if(pre.test(str)){
strList.add(str);
}
}
return strList;
}
方法引用与构造器引用
一、方法引用:若 Lambda 体中的功能,已经有方法提供了实现,可以使用方法引用(可以将方法引用理解为 Lambda 表达式的另外一种表现形式)
语法:
-
对象的引用 :: 实例方法名
-
类名 :: 静态方法名
-
类名 :: 实例方法名
//对象的引用 :: 实例方法名
@Test
public void test2(){
Employee emp = new Employee(101, "张三", 18, 9999.99);
Supplier<String> sup = () -> emp.getName();
System.out.println(sup.get());
System.out.println("----------------------------------");
Supplier<String> sup2 = emp::getName;
System.out.println(sup2.get());
}
//类名 :: 静态方法名
@Test
public void test3(){
BiFunction<Double, Double, Double> fun = (x, y) -> Math.max(x, y);
System.out.println(fun.apply(1.5, 22.2));
System.out.println("----------------------------------------");
BiFunction<Double, Double, Double> fun2 = Math::max;
System.out.println(fun2.apply(1.2, 1.5));
}
/**
* 类名 :: 实例方法名
* 若lambda表达式中有两个参数,第一个参数为实例方法的调用者,第二参数为实例方法的参数时
*/
@Test
public void test5(){
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
System.out.println(bp.test("abcde", "abcde"));
System.out.println("----------------------------------------");
BiPredicate<String, String> bp2 = String::equals;
System.out.println(bp2.test("abc", "abc"));
System.out.println("----------------------------------------");
Function<Employee, String> fun = (e) -> e.show();
System.out.println(fun.apply(new Employee()));
System.out.println("----------------------------------------");
Function<Employee, String> fun2 = Employee::show;
System.out.println(fun2.apply(new Employee()));
}
二、构造器引用 :构造器的参数列表,需要与函数式接口中参数列表保持一致!
语法:类名 :: new
Supplier<Employee> sup = () -> new Employee();
System.out.println(sup.get());
System.out.println("------------------------------------");
//构造器的参数列表,需要与函数式接口中参数列表保持一致!
Supplier<Employee> sup2 = Employee::new;
System.out.println(sup2.get());
三、数组引用
语法:类型[] :: new;
Function<Integer, String[]> fun = (args) -> new String[args];
String[] strs = fun.apply(10);
System.out.println(strs.length);
System.out.println("--------------------------");
Function<Integer, String[]> fun2 = String[] :: new;
String[] strs2 = fun2.apply(20);
System.out.println(strs2.length);
Stream API( java.util.stream .)*
Stream API极大简化了集合框架的处理(但它的处理的范围不仅仅限于集合框架的处理)
流的操作步骤
1)创建流
2)中间操作:不会执行任何操作
3)终止操作:一次性执行全部内容,即”惰性求值“
2)中间操作
筛选与切片
filter————接收lambda。从流中排除某些元素
linit————截断流,元素不超过给定数量
skip(n)————跳过元素,返回一个扔掉了n个元素的流,若流中元素不足n个,则返回空流,与linit互补。
distinct——筛选,通过流所生成元素的hashCode()和equals()去除重复元素。
emps.stream()
.filter((e) -> e.getSalary() > 5000)
.skip(2)
.distinct()
.forEach(System.out::println);
映射
map: 接收lambda,将元素转换为其他形式或者提取信息。接收一个函数作为参数,该函数会被应用每个元素上,并返回一个新的元素
flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有的流合成一个大流
关系类似add() 和addAl()
@Test
public void test2(){
List<String> list = Arrays.asList("aaa","bbb","ccc");
list.stream()
.map(str -> str.toUpperCase())
.forEach(System.out::println);
Stream<Stream<Character>> stream = list.stream()
.map(TestStreamAPI1::filterCharacter);
Stream<Character> stream2 = list.stream()
.flatMap(TestStreamAPI1::filterCharacter);
}
public static Stream<Character> filterCharacter(String str) {
List<Character> list = new ArrayList<>();
for(Character ch:str.toCharArray()){
list.add(ch);
}
return list.stream();
}
排序
sorted() 自然排序 Comparable (按照字典)
sorted(Comparator com) 定制排序
List<String> list = Arrays.asList("ccc","bbb","ddd","aaa");
list.stream()
.sorted()
.forEach(System.out::println);
3)终止操作
allMatch——检查是否匹配所有元素
anyMatch——检查是否至少匹配一个元素
noneMatch——检查是否没有匹配的元素
findFirst——返回第一个元素
findAny——返回当前流中的任意元素
count——返回流中元素的总个数
max——返回流中最大值
min——返回流中最小值
归约——reduce(T identity, BinaryOperator)——可以将流中元素反复结合起来,得到一个值
collect——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
List<Employee> emps = Arrays.asList(
new Employee(102, "李四", 59, 6666.66, Status.BUSY),
new Employee(101, "张三", 18, 9999.99, Status.FREE),
new Employee(103, "王五", 28, 3333.33, Status.VOCATION),
new Employee(104, "赵六", 8, 7777.77, Status.BUSY),
new Employee(104, "赵六", 8, 7777.77, Status.FREE),
new Employee(104, "赵六", 8, 7777.77, Status.FREE),
new Employee(105, "田七", 38, 5555.55, Status.BUSY)
);
//allMatch——检查emps的状态是否全是BUSY
boolean bl=emps.stream()
.allMatch((e) -> e.getStatus().equals(Status.BUSY));
System.out.println(bl); //false
//anyMatch——检查emps的状态是否有一个是BUSY
boolean bl1=emps.stream()
.anyMatch((e) -> e.getStatus().equals(Status.BUSY));
System.out.println(bl1); //true
//noneMatch——检查emps中是否没有状态为BUSY的元素
boolean bl2 = emps.stream()
.noneMatch((e) -> e.getStatus().equals(Status.BUSY));
System.out.println(bl2); //false
//findFirst——返回满足条件的第一个元素
Optional<Employee> op = emps.stream()
.sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
.findFirst();
System.out.println(op.get());
System.out.println("--------------------------------");
//findAny——返回emps中任意满足条件的元素
Optional<Employee> op2 = emps.parallelStream()
.filter((e) -> e.getStatus().equals(Status.FREE))
.findAny();
System.out.println(op2.get());
//count——返回流中元素的总个数
long count = emps.stream()
.filter((e) -> e.getStatus().equals(Status.FREE))
.count();
System.out.println(count);
//获取最高工资 max
Optional<Double> op = emps.stream()
.map(Employee::getSalary)
.max(Double::compare);
System.out.println(op.get());
//获取最低工资的元素信息 min
Optional<Employee> op2 = emps.stream()
.min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(op2.get());
/*
归约 reduce(T identity, BinaryOperator)——可以将流中元素反复结合起来,得到一个值。
获取工资总和
*/
Optional<Double> op = emps.stream()
.map(Employee::getSalary)
.reduce(Double::sum);
System.out.println(op.get());
//收集 collect——将流转换为其他形式
Set<String> set = emps.stream()
.map(Employee::getName)
.collect(Collectors.toSet());
set.forEach(System.out::println);
并行流与串行流:就是把一个内容分成多个数据块,并用不同的线程分 别处理每个数据块的流,可以声明性地通过 parallel() 与 sequential() 在并行流与顺序流之间进行切换。
@Test
public void test3(){
Instant start = Instant.now();
Long sum = LongStream.rangeClosed(0L, 10000000000L)
.parallel()
.sum();
System.out.println(sum);
Instant end = Instant.now();
System.out.println("耗费的时间为: " + (end - start)); //16926
}
接口中的默认方法与静态方法
接口默认方法的”类优先”原则
若一个接口中定义了一个默认方法,而另外一个父类或接口中 又定义了一个同名的方法时 选择父类中的方法。如果一个父类提供了具体的实现,那么 接口中具有相同名称和参数的默认方法会被忽略。 接口冲突。如果一个父接口提供一个默认方法,而另一个接 口也提供了一个具有相同名称和参数列表的方法(不管方法 是否是默认方法),那么必须覆盖该方法来解决冲突
例如 :
//创建两个拥有默认方法的接口
public interface MyFun {
default String getName(){
return "哈哈哈";
}
}
//
public interface MyInterface {
default String getName(){
return "呵呵呵";
}
public static void show(){
System.out.println("接口中的静态方法");
}
}
//创建一个有跟接口的默认方法同名的方法 的类
public class MyClass {
public String getName(){
return "嘿嘿嘿";
}
}
//创建继承 class 和接口的 类
public class SubClass /*extends MyClass*/ implements MyFun, MyInterface{
@Override
public String getName() {
return MyInterface.super.getName();
}
}
//测试
public class TestDefaultInterface {
public static void main(String[] args) {
SubClass sc = new SubClass();
System.out.println(sc.getName());
MyInterface.show();
}
}
新时间日期 API(java.time)
涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作
//1. LocalDate、LocalTime、LocalDateTime
@Test
public void test1(){
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt);
LocalDateTime ld2 = LocalDateTime.of(2019, 02, 21, 10, 10, 10);
System.out.println(ld2);//2019-02-21T10:10:10
LocalDateTime ldt3 = ld2.plusYears(20);
System.out.println(ldt3);//2039-02-21T10:10:10
LocalDateTime ldt4 = ld2.minusMonths(2);
System.out.println(ldt4);//2018-12-21T10:10:10
System.out.println(ldt.getYear());
System.out.println(ldt.getMonthValue());
System.out.println(ldt.getDayOfMonth());
System.out.println(ldt.getHour());
System.out.println(ldt.getMinute());
System.out.println(ldt.getSecond());
}
//2. Instant : 时间戳。 (使用 Unix 元年 1970年1月1日 00:00:00 所经历的毫秒值)
@Test
public void test2(){
Instant ins = Instant.now(); //默认使用 UTC 时区
System.out.println(ins);//2019-02-21T07:21:17.119Z
OffsetDateTime odt = ins.atOffset(ZoneOffset.ofHours(8));
System.out.println(odt);//2019-02-21T15:21:17.119+08:00
System.out.println(ins.getNano());//119000000
Instant ins2 = Instant.ofEpochSecond(5);
System.out.println(ins2);//1970-01-01T00:00:05Z
}
//3.
//Duration : 用于计算两个“时间”间隔
//Period : 用于计算两个“日期”间隔
@Test
public void test3(){
Instant ins1 = Instant.now();
System.out.println("--------------------");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
Instant ins2 = Instant.now();
System.out.println("所耗费时间为:" + Duration.between(ins1, ins2));//所耗费时间为:PT1S
System.out.println("----------------------------------");
LocalDate ld1 = LocalDate.now();
LocalDate ld2 = LocalDate.of(2011, 1, 1);
Period pe = Period.between(ld2, ld1);
System.out.println(pe.getYears());//8
System.out.println(pe.getMonths());//1
System.out.println(pe.getDays());//21
}
//4. TemporalAdjuster : 时间校正器
@Test
public void test4(){
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt);
//将ldt的月改成10
LocalDateTime ldt2 = ldt.withDayOfMonth(10);
System.out.println(ldt2);
//获取下周日的日期
LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println(ldt3);
//自定义:下一个工作日
LocalDateTime ldt5 = ldt.with((l) -> {
LocalDateTime ldt4 = (LocalDateTime) l;
DayOfWeek dow = ldt4.getDayOfWeek();
if(dow.equals(DayOfWeek.FRIDAY)){
return ldt4.plusDays(3);
}else if(dow.equals(DayOfWeek.SATURDAY)){
return ldt4.plusDays(2);
}else{
return ldt4.plusDays(1);
}
});
System.out.println(ldt5);
}
//5. DateTimeFormatter : 解析和格式化日期或时间
@Test
public void test5(){
// DateTimeFormatter dtf = DateTimeFormatter.ISO_LOCAL_DATE;
//自定义时间格式
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss E");
LocalDateTime ldt = LocalDateTime.now();
String strDate = ldt.format(dtf);//2019年02月22日 15:38:13 星期五
System.out.println(strDate);//
//解析回原始格式
LocalDateTime newLdt = ldt.parse(strDate, dtf);
System.out.println(newLdt);//2019-02-22T15:38:13
}
//6.ZonedDate、ZonedTime、ZonedDateTime : 带时区的时间或日期
@Test
public void test7(){
//获取所有的时区
Set set = ZoneId.getAvailableZoneIds();
set.forEach(System.out::println);
LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println(ldt);
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("US/Pacific"));
System.out.println(zdt);
}
重复注解和类型注解
即相同的注解可以在同一地方声明多次。例如:
@Repeatable(MyAnnotations.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@MyAnnotation
public @interface MyAnnotation {
String value() default "";
}
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {
MyAnnotation[] value();
}
public class TestAnnotation {
@Test
public void test1() throws NoSuchMethodException {
Class<TestAnnotation> clazz = TestAnnotation.class;
Method m1 = clazz.getMethod("show");
MyAnnotation[] ma = m1.getAnnotationsByType(MyAnnotation.class);
for(MyAnnotation myAnnotation:ma){
System.out.println(myAnnotation.value());
}
}
@MyAnnotation("hello")
@MyAnnotation("word")
public void show(@MyAnnotation("abc") String str){
}
}
Optional容器类
一、Optional 容器类:用于尽量避免空指针异常
Optional.of(T t) : 创建一个 Optional 实例
Optional.empty() : 创建一个空的 Optional 实例
Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
isPresent() : 判断是否包含值
orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
flatMap(Function mapper):与 map 类似,要求返回值必须是Optional
java9
- 增加对http/2的支持
java10
- 局部变量类型推断
- GC的优化以及内存管理
java11
新特性
jshell
命令提示符快速开发
[图片上传失败...(image-d88499-1551074789807)]
var
java10开始支持,局部变量类型推断;语法的改进,简化编程。
var a = "Hello!";
可推断为String类型
增强方法
- 集合:of()和copyOf()
var list = List.of("Java", "Python", "C");
var copy = List.copyOf(list);
System.out.println(list == copy); // true
var list2 = new ArrayList<String>();
var copy2 = List.copyOf(list);
System.out.println(list2 == copy2); // false
var list3 = List.of();
System.out.println(list3); //[]
copyOf 方法会先判断来源集合是不是 AbstractImmutableList 类型的,如果是,就直接返回,如果不是,则调用 of 创建一个新的集合。
上面演示了 List 的 of 和 copyOf 方法,Set 和 Map 接口都有。
注意:使用of和copyOf创建的集合为不可变集合,不能进行添加、删除、替换、排序等操作,不然会报 java.lang.UnsupportedOperationException 异常。
- 流:
//1.增加单个参数构造方法,可为null
Stream stream2 = Stream.ofNullable(null);
stream2.forEach(System.out::println); //空白
//2.流的迭代 iterate重载
stream2 = Stream.iterate(1,t -> t<5,t -> t+1);
stream2.forEach(System.out::print); //1234
//3.增加 takeWhile 和 dropWhile 方法
//takeWhile() 从流中一直获取判定其为真的元素,一旦元素为假,就终止处理
stream2 = Stream.of(3,9,20,22,40,7);
Stream stream = stream2.takeWhile(t -> t % 2 !=0);
stream.forEach(System.out::println); //3 9
//dropWhile() 从流中一直去除判定其为真的元素,一旦元素为假,就终止去除
stream2 = Stream.of(3,9,20,22,40,7);
stream = stream2.dropWhile(t -> t % 2 !=0);
stream.forEach(System.out::println); //20 22 40 7
- 字符串:
// 判断字符串是否为空白
" ".isBlank(); // true
// 去除首尾空白
" Javastack ".strip(); // "Javastack"
// 去除尾部空格
" Javastack ".stripTrailing(); // " Javastack"
// 去除首部空格
" Javastack ".stripLeading(); // "Javastack "
// 复制字符串
"Java".repeat(3);// "JavaJavaJava"
// 行数统计
"A\nB\nC".lines().count(); // 3
//去除首尾空白.strip()
String string2 = string.strip();//去除字符串首位空白字符,所有输入语言下的空白字符
String string3 = string.trim();//去除字符串首位空白字符,只能去除Unicode码值小于等于32的空白字符
//重复
String string4 = "java";
System.out.println(string4.repeat(3)); //javajavajava
//计算行数
String string6 = "a\nb\nc\n";
System.out.println(string6.lines().count()); //3
//计算行数扩展————原样输出src/file的内容
FileInputStream fis = new FileInputStream("src/file");
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
String string7 = new String(buffer);
string7.lines().forEach(System.out::println);
标准Java异步HTTP客户端
这是 Java 9 开始引入的一个处理 HTTP 请求的的 HTTP Client API,该 API 支持同步和异步,而在 Java 11 中已经为正式可用状态,可以在 java.net 包中找到这个 API
HTTP Client :
1)以编程的方式通过其API用于传输和接受HTTP消息,它对内容是完全不可知的。
2)以可扩展的面向对象的结构实现了HTTP全部的方法(GET, POST等7种方法);
3)设置连接超时的能力;
用法:
@Controller
public class MyController {
@RequestMapping("/test1")
public ResponseEntity<String> test() throws IOException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create("https://www.baidu.com/")).build();
HttpResponse.BodyHandler bodyHandler = HttpResponse.BodyHandlers.ofString();
HttpResponse<String> response = client.send(request,bodyHandler);
String body = response.body();
System.out.println(body);
return new ResponseEntity<String>(body, HttpStatus.OK);
}
//sendAsync
@RequestMapping("/test2")
public ResponseEntity<String> test2() throws IOException, InterruptedException, ExecutionException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create("https://www.qq.com/")).build();
HttpResponse.BodyHandler<String> bodyHandler = HttpResponse.BodyHandlers.ofString();
HttpResponse<String> response = client.sendAsync(request,bodyHandler).get();
// CompletableFuture<HttpResponse> sendAsync = client.sendAsync(request,bodyHandler);
// HttpResponse<String> response = sendAsync.get();
String body = response.body();
System.out.println(body);
return new ResponseEntity<String>(body, HttpStatus.OK);
}
}
5)支持Unicode10
新的Epsilon垃圾收集器和ZGC(还在实验中,生产环境不建议使用)
JFR(Java Flight Recorder)飞行记录仪 (但是生成的文件是后缀为.jfr的二进制文件,需要java12 版本转换才能看)
用法:
在应用启动之后,使用jcmd来录制,比如
$ jcmd <pid> JFR.start
$ jcmd <pid> JFR.dump filename=recording.jfr
$ jcmd <pid> JFR.stop
移除项和废弃项
移除项:已经删除
移除了com.sun.awt.AWTUtilities
移除了sun.misc.Unsafe.defineClass,
使用java.lang.invoke.MethodHandles.Lookup.defineClass来替代
移除了Thread.destroy()以及 Thread.stop(Throwable)方法
移除了sun.nio.ch.disableSystemWideOverlappingFileLockCheck、sun.locale.formatasdefault属性
移除了jdk.snmp模块
移除了javafx
移除了Java Mission Control,从JDK中移除之后,需要自己单独下载
移除了这些Root Certificates :Baltimore Cybertrust Code Signing CA,SECOM ,AOL and Swisscom
废弃项:打算删除
-XX+AggressiveOpts选项
-XX:+UnlockCommercialFeatures 用JFR代替了
-XX:+LogCommercialFeatures选项也不再需要
/
网友评论