某次面试中,面试官问到我这个问题,只勉强说出了 JDK 8 的部分特性,今天就来盘一盘!
画外音:JDK 8 就是 JDK 1.8 版本的意思,后续同理。
Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。
1. 接口增强,default,static 关键字
在 JDK 8 之前接口中只能使用抽象方法,而不能有任何方法的实现。
JDK 8 里面则可以声明 default 和 static 修饰的方法。
/**
* jdk8中接口可以使用声明default和static修饰的方法
* static修饰的方法和普通的方法一样,可以被直接调用
* default修饰的方法有方法体,就和普通的方法一样,可以被重写,有点像抽象类的方法一样,但是java是单继承多实现的
*/
public interface Today {
void dream();
void striver();
default void victory(){
System.out.println("公众号:程序员的成长之路");
}
static void test(){
System.out.println("接口里的静态方法");
}
// jdk9 中还新增了private方法
private void test3() {
System.out.println("私有方法");
};
}
2.Base64 API
Base64 是网络上最常见的用于传输 8Bit 字节码的编码方式之一,Base64 就是一种基于 64 个可打印字符来表示二进制数据的方法,基于 64 个字符 A-Z,a-z,0-9,+,/ 的编码方式,是一种能将任意二进制数据用 64 种字元组合成字符串的方法。
JDK 8 以前的写法
编码和解码的效率比较差,公开信息说以后的版本会取消这个方法。
BASE64Encoder encoder = new BASE64Encoder();
BASE64Decoder decoder = new BASE64Decoder();
byte[] textByte = "公众号:程序员的成长之路".getBytes("UTF-8");
//编码
String encodedText = encoder.encode(textByte);
//5Zyj6a2U5a+85biI(类似这样的)
System.out.println(encodedText);
//解码
//公众号:程序员的成长之路
System.out.println(new String(decoder.decodeBuffer(encodedText),"UTF-8"));
JDK 8 的写法
编解码效率远大于 sun.misc 和 Apache commons Codec,可以自己动收压测一下速度。
Base64.Decoder decoder2 = Base64.getDecoder();
Base64.Encoder encoder2 = Base64.getEncoder();
byte[] textByte2 = "公众号:程序员的成长之路".getBytes("UTF-8");
//编码
String encodedText2 = encoder2.encodeToString(textByte2);
//5Zyj6a2U5a+85biI(类似这样的)
System.out.println(encodedText);
//解码
//公众号:程序员的成长之路
System.out.println(new String(decoder2.decode(encodedText2), "UTF-8"));
3.日期处理类
JDK 8 之前,SimpleDateFormate,Calendar 等类 API涉及比较差,涉及的比较差,日期时间的计算,比较都相对的麻烦,java.util.Date 还是非线程安全的 API。
JDK 8 新增日期处理类:LocalDate、LocalTime、Instant、Duration 以及 Period,这些类都包含在 java.time 包中。
LocalTime localTime = LocalTime.now();
// 现在时间:18:00:49.476
System.out.println("现在时间:"+localTime);
4.Optionnal类
Optional类的作用: 主要解决的问题是:空指针异常 NullPointerException
本质上是一个包含有可选值的包装类,Opertional类既可以为含有对象也可以为空。
import java.util.Optional;
public class Java8Tester {
public static void main(String args[]){
Java8Tester java8Tester = new Java8Tester();
Integer value1 = null;
Integer value2 = new Integer(10);
// Optional.ofNullable - 允许传递为 null 参数
Optional<Integer> a = Optional.ofNullable(value1);
// Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
Optional<Integer> b = Optional.of(value2);
System.out.println(java8Tester.sum(a,b));
}
public Integer sum(Optional<Integer> a, Optional<Integer> b){
// Optional.isPresent - 判断值是否存在
System.out.println("第一个参数值存在: " + a.isPresent());
System.out.println("第二个参数值存在: " + b.isPresent());
// Optional.orElse - 如果值存在,返回它,否则返回默认值
Integer value1 = a.orElse(new Integer(0));
//Optional.get - 获取值,值需要存在
Integer value2 = b.get();
return value1 + value2;
}
}
输出结果为:
第一个参数值存在: false
第二个参数值存在: true
10
5.方法引用
方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
方法引用使用一对冒号 :: 。
构造器引用,它的语法是Class::new,或者更一般的Class< T >::new实例如下:
Demo demo = Demo::new;
静态方法引用,它的语法是Class::static_method,实例如下:
Demo::静态方法();
特定类的任意对象的方法引用:它的语法是Class::method实例如下:
Demo::方法名();
特定对象的方法引用:它的语法是instance::method实例如下:
demo::方法名();
6.Lambda 与 函数式编程
函数式编程
================== 自定义函数是编程(1) ====================
/**
* 像Runnable接口一样用FunctionalInterface注解修饰
* 加了这个注解后,接口里面必须有且只能有一个方法
*/
@FunctionalInterface
public interface Test1<R,T>{
// R表示返回值,T表示参数类型,t1 t2是具体参数
R operator(T t1, T t2);
}
public class Compute {
/**
* 定义一个函数方法
* 需要传入a和b两个参数,
* 后面的Test1<Integer,Integer> of就是传入的一个函数(行为),of是随便起的一个别名
*/
public static Integer operator(Integer a,Integer b,Test1<Integer,Integer> of){
return of.operator(a,b);
}
}
public class Main {
public static void main(String[] args) throws Exception {
System.out.println(Compute.operator(2,3,(a,b)-> a+b));
System.out.println(Compute.operator(2,3,(a,b)-> a-b));
System.out.println(Compute.operator(2,3,(a,b)-> a*b));
System.out.println(Compute.operator(2,3,(a,b)-> a/b));
}
}
================== 自定义函数是编程(2) ====================
@FunctionalInterface
public interface Test2{
void test();
}
public class Main {
public static void main(String[] args) throws Exception {
Main.casesc(()-> System.out.println("函数式编程案例二"));
}
public static void casesc(Test2 t){
t.test();
}
}
Lambda
public static void main(String[] args) throws Exception {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("jdk8以前创建线程");
}
});
//()对应run()没有一个参数,->后面是方法体内容
//如果{}中的代码只有⼀行,⽆论有返回值,可以省略{}、return、分号,其他则需要加上
new Thread(()-> System.out.println("lambda表达式创建线程"));
List<String> list = Arrays.asList("a","c","d","b","e");
// jdk8以前排序
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
});
// lambda表达式排序
//,前面的对应接口前面的参数,a b 对应compare里面的参数
Collections.sort(list,(a,b)->b.compareTo(a));
}
7. 四大核心函数式接口
Lambda表达式必须先定义接口,创建相关方法之后才能调用,这样做十分不便,其实java8已经内置了许多接口, 例如下面四个功能型接口.所有标注@FunctionalInterface注解的接口都是函数式接口。
Consumer 消费型接口:有入参,无返回值。适用场景:因为没有出参,常⽤用于打印、发送短信等消费。
public class Main {
public static void main(String[] args) throws Exception {
Consumer<String> c1 = obj->System.out.println(obj+": 调⽤用短信接⼝口发送短信,或者打印⽇日志");
c1.accept("订单id—001");
Consumer<List> c2 = obj->{
if(obj==null || obj.size()<1)return;
obj.forEach(o-> System.out.println(o));
};
List<Integer> list = Arrays.asList(2,4,0,8,9,7);
c2.accept(list);
}
}
Supplier 供给型接口:无入参,有返回值。适用场景:泛型一定和方法的返回值类型是同一种类型,并且不需要传入参数,例如:无参的工厂方法。
public class Main {
public static void main(String[] args) throws Exception {
Student student = newStudent();
System.out.println(student);
}
public static Student newStudent(){
Supplier<Student> supplier = ()-> {
Student student = new Student();
student.setName("默认名称");
return student;
};
return supplier.get();
}
}
class Student{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
}
Function与BiFunctionObj 函数型接口:有入参,有返回值。适用场景:传入参数经过函数的计算返回另一个值。
Function:只能接受一个参数
用法一(用一个类实现接口里面的逻辑,然后直接调用)
public class FunctionObj implements Function {
@Override
public Object apply(Object o) {
return "对参数:"+o+"经过处理后返回结果";
}
}
public class Main {
public static void main(String[] args) throws Exception {
System.out.println(test("hello",new FunctionObj()));
}
public static String test(String a ,FunctionObj functionObj){
return functionObj.apply(a).toString();
}
}
用法二(左边规定好参数和返回值类型,右边写方法体具体逻辑)
public class Main {
public static void main(String[] args) throws Exception {
Function<Integer,Integer> func = p->{
return p*100;
};
System.out.println(func.apply(12));
Function<Integer,Boolean> function = a->a<100;
System.out.println(function.apply(97));
}
}
=================================================================
BiFunctionObj:能接受两个参数
// 用法一
public class BiFunctionObj implements BiFunction {
@Override
public Object apply(Object o, Object o2) {
return (Integer.valueOf(o.toString())+Integer.valueOf(o2.toString()));
}
}
public class Main {
public static void main(String[] args) throws Exception {
System.out.println(test(2,5,new BiFunctionObj()));
}
public static Integer test(Integer a,Integer b, BiFunctionObj func){
return Integer.valueOf(func.apply(a,b).toString());
}
}
// 用法二
public class Main {
public static void main(String[] args) throws Exception {
BiFunction<Integer, Integer,Boolean> func1 = (a,b)->{
return a>b;
};
System.out.println(func1.apply(1,5));
BiFunction<String, String,String> func2 = (a,b)->a+b;
System.out.println(func2.apply("hellow","world"));
}
}
Predicate 断言型接口:有入参,有返回值,返回值类型确定是boolean。适用场景:接收一个参数,用于判断是否满一定的条件,过滤数据。
public class Main {
public static void main(String[] args) throws Exception {
Predicate<Integer> predicate = a->a>10;
List<Integer> list = Arrays.asList(1,54,9,34,3);
for(Integer l : list){
if(predicate.test(l)) System.out.println(l);
}
}
}
8.流操作
Stream:通过将集合转换为这么⼀种叫做 “流”的元素队列,能够对集合中的每个元素进行任意操作。
总共分为4个步骤:
一般都采用stream,因为集合操作一般里面就几百条数据,多线程的并行流效率不一定就高,还会出现线程安全问题。
public class Main {
public static void main(String[] args) {
List<String> list = Arrays.asList("张麻子","李蛋","王二狗","Angell");
List<Student> users = Arrays.asList(new Student("张三", 23),
new Student("赵四", 24),
new Student("二狗", 23),
new Student("田七", 22),
new Student("皮特", 20),
new Student("Tony", 20),
new Student("二柱子", 25));
/**
* map:对集合的每个对象做处理
*/
List<String> collect = list.stream().map(obj->"哈哈"+obj).collect(Collectors.toList());
list.forEach(obj->System.out.println(obj));
System.out.println("----------------");
collect.forEach(obj->System.out.println(obj));
/**
* filter:boolean判断,用于条件过滤
*/
System.out.println("----------------");
Set<String> set = list.stream().filter(obj->obj.length()>2).collect(Collectors.toSet());
set.forEach(obj->System.out.println(obj));
/**
* sorted:对流进行自然排序
*/
System.out.println("----------------");
Set<String> sorteds = list.stream().sorted().collect(Collectors.toSet());
sorteds.forEach(obj->System.out.println(obj));
// 自定义排序规则
// 根据长度排序(正序)
System.out.println("----------------");
List<String> resultList = list.stream().sorted(Comparator.comparing(obj -> obj.length())).collect(Collectors.toList());
resultList.forEach(obj->System.out.println(obj));
System.out.println("----------------");
// 根据长度排序(倒序)
List<String> resultList2 = list.stream().sorted(Comparator.comparing(obj -> obj.length(),Comparator.reverseOrder())).collect(Collectors.toList());
resultList2.forEach(obj->System.out.println(obj));
System.out.println("----------------");
// 手动指定排序规则(根据年龄大小排序)
List<Student> collect2 = users.stream().sorted(
Comparator.comparing(Student::getAge,(x,y)->{
if(x>y) {
return 1;
}else {
return -1;
}
})
).collect(Collectors.toList());
collect2.forEach(obj->System.out.println(obj.getAge()+" : "+obj.getProvince()));
/**
* limit:截取包含指定数量的元素
*/
System.out.println("----------------");
List<String> collect3 = list.stream().limit(2).collect(Collectors.toList());
collect3.forEach(obj->System.out.println(obj));
/**
* allMatch:匹配所有元素,只有全部符合才返回true
*/
System.out.println("----------------");
boolean flag = list.stream().allMatch(obj->obj.length()>2);
System.out.println(flag);
System.out.println("----------------");
/**
* anyMatch:匹配所有元素,至少一个元素满足就为true
*/
boolean flag2 = list.stream().anyMatch(obj->obj.length()>2);
System.out.println(flag2);
System.out.println("----------------");
/**
* max和min:最大值和最小值
*/
Optional<Student> max = users.stream().max(Comparator.comparingInt(Student::getAge));
System.out.println(max.get().getAge()+" : "+max.get().getProvince());
System.out.println("----------------");
Optional<Student> min = users.stream().min((s1, s2)->Integer.compare(s1.getAge(),s2.getAge()));
System.out.println(min.get().getAge()+" : "+min.get().getProvince());
/**
* reduce:对Stream中的元素进行计算后返回一个唯一的值
*/
// 计算所有值的累加
int value = Stream.of(1, 2, 3, 4, 5).reduce((item1, item2) -> item1 + item2).get();
// 100作为初始值,然后累加所有值
int value2 =Stream.of(1, 2, 3, 4, 5).reduce(100, (sum, item) -> sum + item);
// 找出最大值
int value3 =Stream.of(1, 4, 5, 2, 3).reduce((x,y)->x>y?x:y).get();
System.out.println(value);
System.out.println(value2);
System.out.println(value3);
}
}
class Student {
private String province;
private int age;
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(String province, int age) {
this.age = age;
this.province = province;
}
}
9.终端操作收集器:Collector
/**
* 数据结构收集:Collectors
*/
public class Main {
public static void main(String[] args) throws Exception {
List<String> data = Arrays.asList("张三","王五","李四");
List<String> list = data.stream().collect(Collectors.toList());
Set<String> set = data.stream().collect(Collectors.toSet());
LinkedList<String> linkedList = data.stream().collect(Collectors.toCollection(LinkedList::new));
System.out.println(list);
System.out.println(set);
System.out.println(linkedList);
/*
Collectors.toMap()
Collectors.toSet()
Collectors.toCollection() :⽤用⾃自定义的实现Collection的数据结构收集
Collectors.toCollection(LinkedList::new)
Collectors.toCollection(CopyOnWriteArrayList::new)
Collectors.toCollection(TreeSet::new)
*/
}
}
//============================================================
/**
* 拼接函数:joining
*/
public class Main {
public static void main(String[] args) throws Exception {
List<String> list = Arrays.asList("springBoot","springCloud","netty");
String result1 = list.stream().collect(Collectors.joining());
String result2 = list.stream().collect(Collectors.joining("——"));
String result3 = list.stream().collect(Collectors.joining("—", "【",""));
String result4 = Stream.of("hello", "world").collect(Collectors.joining("—", "【", "】"));
System.out.println(result1);
System.out.println(result2);
System.out.println(result3);
System.out.println(result4);
}
}
//============================================================
/**
* 分组:partitioningBy
*/
public class Main {
public static void main(String[] args) throws Exception {
List<String> list = Arrays.asList("sdfsdf","xxxx","bbb","bbb");
Map<Boolean, List<String>> collect = list.stream().collect(Collectors.partitioningBy(obj -> obj.length() > 3));
System.out.println(collect);
}
}
//============================================================
/**
* 分组:group by
* 统计:counting
*/
public class Main {
public static void main(String[] args) throws Exception {
List<Student> students = Arrays.asList( new Student("⼴东", 23),
new Student("⼴东", 24),
new Student("⼴东", 23),
new Student("北京", 22),
new Student("北京", 20),
new Student("北京", 20),
new Student("海南", 25));
// 通过名称分组
Map<String, List<Student>> listMap = students.stream().collect(Collectors.groupingBy(obj -> obj.getProvince()));
listMap.forEach((key, value) -> {
System.out.println("========");
System.out.println(key);
value.forEach(obj -> {
System.out.println(obj.getAge());
});
});
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
// 根据名称分组,并统计每个分组的个数
Map<String, Long> map = students.stream().collect(Collectors.groupingBy(Student::getProvince, Collectors.counting()));
map.forEach((key,value)->{
System.out.println(key+"省人数有"+value);
});
}
}
class Student {
private String province;
private int age;
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(String province, int age) {
this.age = age;
this.province = province;
}
}
//============================================================
/**
* 统计函数:summarizing
*/
public class Main {
public static void main(String[] args) throws Exception {
List<Student> students = Arrays.asList( new Student("⼴东", 23),
new Student("⼴东", 24),
new Student("⼴东", 23),
new Student("北京", 22),
new Student("北京", 20),
new Student("北京", 20),
new Student("海南", 25));
// summarizingInt;summarizingLong;summarizingDouble
IntSummaryStatistics summaryStatistics = students.stream().collect(Collectors.summarizingInt(Student::getAge));
System.out.println("平均值:" + summaryStatistics.getAverage());
System.out.println("人数:" + summaryStatistics.getCount());
System.out.println("最大值:" + summaryStatistics.getMax());
System.out.println("最小值:" + summaryStatistics.getMin());
System.out.println("总和:" + summaryStatistics.getSum());
}
}
/**
* reduce:对Stream中的元素进行计算后返回一个唯一的值
*/
// 计算所有值的累加
int value = Stream.of(1, 2, 3, 4, 5).reduce((item1, item2) -> item1 + item2).get();
// 100作为初始值,然后累加所有值
int value2 =Stream.of(1, 2, 3, 4, 5).reduce(100, (sum, item) -> sum + item);
// 找出最大值
int value3 =Stream.of(1, 4, 5, 2, 3).reduce((x,y)->x>y?x:y).get();
System.out.println(value);
System.out.println(value2);
System.out.println(value3);
JDK 9 发布于 2017 年 9 月 22 日,带来了很多新特性,其中最主要的变化是已经实现的模块化系统。
1. try-with-resource
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class Main {
public static void main(String[] args) throws Exception {
String path = "/Users/jack/Desktop/t.txt";
/**
* jdk 1.7以前关闭资源一般是在finally里面操作的
*/
OutputStream out = new FileOutputStream(path);
try {
out.write(("公众号:程序员的成长之路").getBytes());
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* jdk1.7的时候,可以在try()里声明资源,会在try-catch代码块结束后自动关闭掉。
* try结束后自动调用的close方法,这个动作会早于finally里调用的方法
* bu管是否出现异常,try()里的实例都会被调用close方法
* try里面可以声明多个自动关闭的对象,越早声明的对象,会越晚被close掉
*/
try (OutputStream out2 = new FileOutputStream(path);){
out2.write(("公众号:程序员的成长之路").getBytes());
} catch (Exception e) {
e.printStackTrace();
}
/**
* jdk1.9之后,对try()做了改进,在try外进行初始化,在括号内引用
*/
OutputStream out3 = new FileOutputStream(path);
try (out3) {
out3.write(("公众号:程序员的成长之路").getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}
}
2. stream
public class Main {
/**
* jdk9中的Stream流新增了两个api
*/
public static void main(String[] args) throws Exception {
/**
* takeWhile:遍历每个对象,直到遇到第⼀个false时,返回前面所有元素,如果没有false,将返回⼀一个空的 Stream
*/
List<String> list1 = List.of("springboot","java","html","","git").stream()
.takeWhile(obj->!obj.isEmpty()).collect(Collectors.toList());
System.out.println(list1);
/**
* dropWhile:与takeWhile相反
*/
List<String> list2 = List.of("springboot","java","html","","git").stream()
.dropWhile(obj->!obj.isEmpty()).collect(Collectors.toList());
System.out.println(list2);
}
}
3. of 创建只读集合
public class Main {
public static void main(String[] args) throws Exception {
/**
* JDK9之前创建只读集合
*/
List<String> list = new ArrayList<String>();
list.add("张三");
list.add("李四");
list.add("王五");
list.remove(0);
System.out.println(list);
//设置为只读List集合
// unmodifiableMap(map); unmodifiableMap(set);
list = Collections.unmodifiableList(list);
// 报错:java.lang.UnsupportedOperationException
//list.remove(0);
System.out.println(list);
/**
* jdk9创建只读集合
*/
List<String> list2 = List.of("mysql", "linux", "redis");
list2.remove(0);
System.out.println(list2);
}
}
自从 Java 9 开始,Oracle 调整了 Java 版本的发布策略,不再是之前的 N 年一个大版本,取而代之的是 6 个月一个小版本,三年一个大版本,这样可以让 Java 的最新改变迅速上线,而小版本的维护周期缩短到下个版本发布之前,大版本的维护周期则是 3 年之久。
2018 年 3 月 20 日,Oracle 宣布 Java 10 正式发布。
1. var作为局部变量类型推断标识符
public class Main {
// var作为局部变量类型推断标识符
public static void main(String[] args) throws Exception {
var strVar = "springboot";
System.out.println(strVar instanceof String);
//根据10L 推断long 类型
var longVar = Long.valueOf(10l);
System.out.println(longVar instanceof Long);
//根据 true推断 boolean 类型
var flag = Boolean.valueOf("true");
System.out.println(flag instanceof Boolean);
// 推断 ArrayList<String>
var listVar = new ArrayList<String>();
System.out.println(listVar instanceof ArrayList);
// 推断 Stream<String>
var streamVar = Stream.of("aa", "bb", "cc");
System.out.println(streamVar instanceof Stream);
if(flag){
System.out.println("这个是 flag 变量,值为true");
}
for (var i = 0; i < 10; i++) {
System.out.println(i);
}
try (var input = new FileInputStream("validation.txt")) {
}
}
}
2018-09-26,Oracle官方宣布Java 11 (18.9 LTS)正式发布,这是自Java 8后推出的首个长期支持版本。根据官方公布的路线图,Java 11将会获得Oracle提供的长期支持服务,直至2026年9月。
1. httpclinet
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
/**
* 这个功能在JDK9中引入,在JDK10中得到了更新,在JDK11才发布
*/
public class Main {
private static final URI uri = URI.create("https://www.cnblogs.com/wlwl/");
public static void main(String[] args) {
testHttp2();
}
/**
* get请求
*/
private static void testGet() {
// 创建连接两种方式:var httpClient = HttpClient.newHttpClient();
var httpClient = HttpClient.newBuilder().connectTimeout(Duration.ofMillis(5000)).build();
// 封装请求参数(默认get请求)
HttpRequest request = HttpRequest.newBuilder().timeout(Duration.ofMillis(3000))
.header("key1", "v1")
.uri(uri).build();
try {
var response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* post请求
*/
private static void testPost() {
HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder().uri(uri)
.POST(HttpRequest.BodyPublishers.ofString("phone=13113777337&pwd=1234567890"))
// from表单要用下面格式发送
//.header("Content-Type", "application/json")
//.POST(HttpRequest.BodyPublishers.ofString("{\"phone\":\"13113777337\",\"pwd\":\"1234567890\"}"))
.build();
try {
var response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 异步GET请求
*/
private static void testAsynGet() {
var httpClient = HttpClient.newBuilder().build();
var request =
HttpRequest.newBuilder().timeout(Duration.ofMillis(3000))
.header("key1", "v1")
.uri(uri).build();
try {
// 异步请求通过CompletableFuture实现
CompletableFuture<String> result = httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body);
System.out.println(result.get());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 发送http2请求
* HTTP2协议的强制要求https,如果目标URI是HTTP的,则无法使用HTTP 2协议
*/
private static void testHttp2() {
var httpClient = HttpClient.newBuilder().connectTimeout(Duration.ofMillis(3000))
.version(HttpClient.Version.HTTP_2)
.build();
var request = HttpRequest.newBuilder().timeout(Duration.ofMillis(3000))
.header("key1", "v1")
.uri(uri)
.build();
try {
var response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
System.out.println(response.version());
} catch (Exception e) {
e.printStackTrace();
}
}
}
2019-03-20,JDK 12 正式发布,新特性如下:
1.Switch 表达式
使用Java 12,switch不仅可以作为语句也可以作为表达式。无论作为语句或者作为表达式,switch都可以使用传统/简化的作用域和控制流行为。这将有助于简化代码,并为在switch中使用模式匹配铺平道路。
Java开发人员正在增强Java编程语言,以使用模式匹配来解决当前switch语句的几个问题。这包括:switch块的默认控制流行为,switch块默认作用域(被视为单个作用域的块)和switch仅作为语句。
在Java 11中,switch语句追随C和C++,默认情况下使用fall-through语义。虽然传统的控制流程在编写低级代码时很有用,但随着switch在更高级别的环境中采用,易出错会盖过其灵活性。
Java 11
Java 12
2.默认CDS归档
通过在64位平台上的默认类列表的帮助下生成CDS归档来改进JDK构建过程,从而有效地消除了运行java -Xshare:dump。此功能的目标包括:1。)改进开箱即用的启动时间,以及2.)摆脱使用-Xshare:dump。
3.Shenandoah GC
Shenandoah是一种垃圾收集(GC)算法,旨在保证低延迟(10 - 500 ms的下限)。它通过在运行Java工作线程的同时执行GC操作减少GC暂停时间。使用Shenandoah,暂停时间不依赖于堆的大小。这意味着无论堆的大小如何,暂停时间都是差不多的。
这是一个实验性功能,不包含在默认(Oracle)的OpenJDK版本中。
4.JMH 基准测试
此功能为JDK源代码添加了一套微基准测试(大约100个),简化了现有微基准测试的运行和新基准测试的创建过程。它基于Java Microbenchmark Harness(JMH)并支持JMH更新。
此功能使开发人员可以轻松运行当前的微基准测试并为JDK源代码添加新的微基准测试。可以基于Java Microbenchmark Harness(JMH)轻松测试JDK性能。它将支持JMH更新,并在套件中包含一组(约100个)基准测试。
5.JVM 常量 API
JEP 334引入了一个API,用于建模关键类文件和运行时artifacts,例如常量池。此API将包括ClassDesc,MethodTypeDesc,MethodHandleDesc和DynamicConstantDesc等类。此 API 对于操作类和方法的工具很有帮助。
6.G1的可中断 mixed GC
此功能通过将Mixed GC集拆分为强制部分和可选部分,使G1垃圾收集器更有效地中止垃圾收集过程。通过允许垃圾收集过程优先处理强制集,g1可以更多满足满足暂停时间目标。
G1是一个垃圾收集器,设计用于具有大量内存的多处理器机器。由于它提高了性能效率,g1垃圾收集器最终将取代cms垃圾收集器。
G1垃圾收集器的主要目标之一是满足用户设置的暂停时间。G1采用一个分析引擎来选择在收集期间要处理的工作量。此选择过程的结果是一组称为GC集的区域。一旦GC集建立并且GC已经开始,那么G1就无法停止。
如果G1发现GC集选择选择了错误的区域,它会将GC区域的拆分为两部分(强制部分和可选部分)来切换到处理Mix GC的增量模式。如果未达到暂停时间目标,则停止对可选部分的垃圾收集。
7.G1归还不使用的内存
此功能的主要目标是改进G1垃圾收集器,以便在不活动时将Java堆内存归还给操作系统。为实现此目标,G1将在低应用程序活动期间定期生成或持续循环检查完整的Java堆使用情况。
这将立即归还未使用的部分Java堆内存给操作系统。用户可以选择执行FULL GC以最大化返回的内存量。
8.移除多余ARM64实现
Java 12将只有一个ARM 64位实现(aarch64)。目标是删除所有与arm64实现相关的代码,同时保留32位ARM端口和64位aarch64实现。
这将把重点转移到单个64位ARM实现,并消除维护两个实现所需的重复工作。当前的JDK 11实现中有两个64位ARM实现。
2019-09-17,JDK 12 正式发布,新特性如下:
1. switch
public class Main {
public static void main(String[] args) {
testOldSwitch1();
}
/**
* 旧:没有break,则匹配的case后⾯面会⼀一直输出
*/
public static void testOldSwitch1(){
int i = 1;
switch(i){
case 0:
System.out.println("zero");
//break;
case 1:
System.out.println("one");
//break;
case 2:
System.out.println("two");
//break;
default:
System.out.println("default");
}
}
/**
* 新:使用箭头函数,不用声明break,会自动终止,支持多个值匹配,使用逗号分隔
*/
public void testNewSwitch(int i){
switch(i){
case 0 -> {
System.out.println("zero");
System.out.println("这是多⾏行行语句句");
}
case 1,11,111 -> System.out.println("one");
case 2 -> System.out.println("two");
default -> System.out.println("default");
}
}
}
2. 多行文本块
public class Main {
public static void main(String[] args) {
/**
* 旧:在java代码里面编写多行源码带有特殊字符则需要转义,如HTML,sql等
*/
String html = "<html>\n" +
"<body>\n" +
"<p>Hello, world</p>\n" +
"</body>\n" +
"</html>\n";
String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" +
"WHERE `CITY` = 'INDIANAPOLIS'\n" +
"ORDER BY `EMP_ID`, `LAST_NAME`;\n";
/**
* 新:不用对转义字符进行转义
*/
String html2 = """"
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
String query = """
SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
WHERE `CITY` = 'INDIANAPOLIS'
ORDER BY `EMP_ID`, `LAST_NAME`;
""";
}
}
收集整理的信息不全,又不正确的地方,欢迎指出!