JDK 的前世今生:细数 Java5 - 15 的那些经典特性,java 高级程序员的要求
<singer name='eason' age='10'></singer>
</list>ENDDOCUMENT
6. Common Annotations
?
Common annotations 原本是 Java EE 5.0(JSR 244)规范的一部分,现在 SUN 把它的一部分放到了 Java SE 6.0 中。随着 Annotation 元数据功能加入到 Java SE 5.0 里面,很多 Java 技术都会用 Annotation 部分代替 XML 文件来配置运行参数。
?
以下列举 Common Annotations 1.0 里面的几个 Annotations:
@Generated:用于标注生成的源代码
@Resource: 用于标注所依赖的资源,容器据此注入外部资源依赖,有基于字段的注入和基于 setter 方法的注入两种方式 。
@Resources:同时标注多个外部依赖,容器会把所有这些外部依赖注入
@PostConstruct:标注当容器注入所有依赖之后运行的方法,用来进行依赖注入后的初始化工作,只有一个方法可以标注为 PostConstruct 。
@PreDestroy:当对象实例将要被从容器当中删掉之前,要执行的回调方法要标注为 PreDestroy
7. Compiler API
javac 编译器可以把.java 的源文件编译为.class 文件,JDK 6 的新特性 Compiler API(JSR 199)也可以动态编译 Java 源文件。
public class CompilerApiTest {
public static void main(String[] args) throws Exception {
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardJavaFileManager = javaCompiler.getStandardFileManager(null,null,null);
Iterable<? extends JavaFileObject> javaFileObjects = standardJavaFileManager.getJavaFileObjects("C:\Singer.java");
javaCompiler.getTask(null, standardJavaFileManager, null, null, null, javaFileObjects).call();
standardJavaFileManager.close();
}
}
运行结果:会在 C 目录生成 Singer.class 文件
8. 对脚本语言的支持(如: ruby, groovy, javascript)
JDK6 增加了对脚本语言的支持(JSR 223),原理是将脚本语言编译成字节码,这样脚本语言也能享用 Java 平台的诸多优势,包括可移植性,安全等。JDK6 实现包含了一个基于 Mozilla Rhino 的 脚本语言引擎,因此可以支持 javascript,当然 JDK 也支持 ruby 等其他语言
public class JavaScriptTest {
public static void main(String[] args) throws Exception {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
String script;
try {
script = "print('Hello')";
engine.eval(script);// 执行脚本
}catch (Exception e) {
e.printStackTrace();
}
}
}
//output
Hello
Java 7 新特性
1.switch 支持 String 字符串类型。
String singer = "jay";
switch (singer) {
case "jay" :
System.out.println("周杰伦");
break;
case "eason" :
System.out.println("陈奕迅");
break ;
default :
System.out.println("其他");
break ;
}
2.try-with-resources,资源自动关闭
JDK 7 之前:
BufferedReader br = new BufferedReader(new FileReader("d:七里香.txt"));
try {
return br.readLine();
} finally {
br.close();
}
JDK 7 之后:
/*
声明在 try 括号中的对象称为资源,在方法执行完毕后会被自动关闭
*/
try (BufferedReader br = new BufferedReader(new FileReader("d:七里香.txt")) {
return br.readLine();
}
3. 整数类型如(byte,short,int,long)能够用二进制来表示
//0b 或者 0B 表示二进制
int a = 0b010;
int b = 0B010;
4. 数字常量支持下划线
int a = 11_11;//a 的值为 1111,下划线不影响实际值,提升可读性
5. 泛型实例化类型自动推断,即”<>”
JDK 7 之前:
Map<String, List<String>> map = new HashMap<String, List<String>>();
JDK 7 之后:
//不须声明类型,自动根据前面<>推断其类型
Map<String, List<String>> map = new HashMap<>();
6.一个 catch 中捕获多个异常类型,用(|)分隔开
JDK 7 之前
try{
//do something
} catch (FirstException e) {
logger.error(e);
} catch (SecondException e) {
logger.error(ex);
}
JDk 7 之后
try{
//do something
} catch (FirstException | SecondException e) {
logger.error(e);
}
7. 增强的文件系统
Java7 提供了全新的 NIO2.0 API,方便文件管理的编码。如,可以在 java.nio.file 包下使用 Path、Paths、Files、WatchService 等常用类型。
Path path = Paths.get("C:\jay\七里香.txt"); //创建 Path 对象
byte[] bytes= Files.readAllBytes(path); //读取文件
System.out.println(path.getFileName()); //获取当前文件名称
System.out.println(path.toAbsolutePath()); // 获取文件绝对路径
System.out.println(new String(bytes, "utf-8"));
8. Fork/join 框架
Java7 提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。
Fork/join 计算 1-1000 累加值:
public class ForkJoinPoolTest {
private static final Integer DURATION_VALUE = 100;
static class ForkJoinSubTask extends RecursiveTask<Integer>{
// 子任务开始计算的值
private Integer startValue;
// 子任务结束计算的值
private Integer endValue;
private ForkJoinSubTask(Integer startValue , Integer endValue) {
this.startValue = startValue;
this.endValue = endValue;
}
@Override
protected Integer compute() {
//小于一定值 DURATION,才开始计算
if(endValue - startValue < DURATION_VALUE) {
System.out.println("执行子任务计算:开始值 = " + startValue + ";结束值 = " + endValue);
Integer totalValue = 0;
for (int index = this.startValue; index <= this.endValue; index++) {
totalValue += index;
}
return totalValue;
} else {
// 将任务拆分,拆分成两个任务
ForkJoinSubTask subTask1 = new ForkJoinSubTask(startValue, (startValue + endValue) / 2);
subTask1.fork();
ForkJoinSubTask subTask2 = new ForkJoinSubTask((startValue + endValue) / 2 + 1 , endValue);
subTask2.fork();
return subTask1.join() + subTask2.join();
}
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
// Fork/Join 框架的线程池
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<Integer> taskFuture = pool.submit(new ForkJoinSubTask(1,1000));
Integer result = taskFuture.get();
System.out.println("累加结果是:" + result);
}
}
运行结果:
...
执行子任务计算:开始值 = 189;结束值 = 250
执行子任务计算:开始值 = 251;结束值 = 313
执行子任务计算:开始值 = 314;结束值 = 375
执行子任务计算:开始值 = 376;结束值 = 438
执行子任务计算:开始值 = 439;结束值 = 500
执行子任务计算:开始值 = 501;结束值 = 563
执行子任务计算:开始值 = 564;结束值 = 625
执行子任务计算:开始值 = 626;结束值 = 688
执行子任务计算:开始值 = 689;结束值 = 750
执行子任务计算:开始值 = 751;结束值 = 813
执行子任务计算:开始值 = 814;结束值 = 875
执行子任务计算:开始值 = 876;结束值 = 938
执行子任务计算:开始值 = 939;结束值 = 1000
累加结果是:500500
Java 8 新特性
1.lambada 表达式
Lambda 允许把函数作为一个方法的参数,传递到方法中
语法格式:
(parameters) -> expression 或 (parameters) ->{ statements; }
代码示例:
Arrays.asList("jay", "Eason", "SHE").forEach(
( String singer ) -> System.out.print( singer + ",") );
2. 函数式接口
Lambda 的设计者为了让现有的功能与 Lambda 表达式很好兼容,设计出函数式接口。
函数式接口是指只有一个函数的接口,可以隐式转换为 lambada 表达式。
Java 8 提供了注解 @FunctionalInterface,显示声明一个函数式接口。
java.lang.Runnable 和 java.util.concurrent.Callable 是函数式接口的例子~
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
3. 方法引用
方法引用提供了非常有用的语法,可以直接引用已有 Java 类或对象(实例)的方法或构造器。它与 Lambda 表达式配合使用,可以减少冗余代码,使代码更加简洁。
//利用函数式接口 Consumer 的 accept 方法实现打印,Lambda 表达式如下
Consumer<String> consumer = x -> System.out.println(x);
consumer.accept("jay");
//引用 PrintStream 类(也就是 System.out 的类型)的 println 方法,这就是方法引用
consumer = System.out::println;
consumer.accept("私信资料,领一线大厂面试专题");
4. 默认方法
默认方法就是一个在接口里面有了一个实现的方法。它允许将新方法添加到接口,但不强制实现了该接口的类必须实现新的方法。
public interface ISingerService {
// 默认方法
default void sing(){
System.out.println("唱歌");
}
void writeSong();
}
//JaySingerServiceImpl 不用强制实现 ISingerService 的默认 sing()方法
public class JaySingerServiceImpl implements ISingerService {
@Override
public void writeSong() {
System.out.println("写了一首七里香");
}
}
5.Stream API
Stream API,支持对元素流进行函数式操作,它集成在 Collections API 中,可以对集合进行批量操作。常用 API:
filter 筛选
map 流映射
reduce 将流中的元素组合起来
collect 返回集合
sorted 排序
flatMap 流转换
limit 返回指定流个数
distinct 去除重复元素
public class Singer {
private String name;
private Integer songNum;
private Integer age;
...
}
List<Singer> singerList = new ArrayList<Singer>();
singerList.add(new Singer("jay", 11, 36));
singerList.add(new Singer("eason", 8, 31));
singerList.add(new Singer("JJ", 6, 29));
List<String> singerNameList = singerList.stream()
.filter(singer -> singer.getAge() > 30) //筛选年龄大于 30
.sorted(Comparator.comparing(Singer::getSongNum)) //根据歌曲数量排序
.map(Singer::getName) //提取歌手名字
.collect(Collectors.toList()); //转换为 List
6. Optional
Java 8 引入 Optional 类,用来解决 NullPointerException。Optional 代替 if…else 解决空指针问题,使代码更加简洁。
if…else 判空
Singer singer = getSingerById("666");
if (singer != null) {
String name = singer.getName();
System.out.println(name);
}
Optional 的判空
Optional<Singer> singer = Optional.ofNullable(getSingerById("666"));
singer.ifPresent(s -> System.out.println(s.getName()));
7. Date Time API
JDK 8 之前的日期 API 处理存在非线程安全、时区处理麻烦等问题。Java 8 在 java.time 包下提供了新的日期 API,简化了日期的处理~
LocalDate today = LocalDate.now();
int year = today.getYear();
System.out.println("今年是" + year);
//是否闰年
System.out.println("今年是不是闰年:" + today.isLeapYear());
LocalDateTime todayTime = LocalDateTime.now();
System.out.println("当前时间" + todayTime);
//时区指定
System.out.println("美国时间:" + ZonedDateTime.of(todayTime,ZoneId.of("America/Los_Angeles")));
LocalDate specailDate = LocalDate.of(2020, 6, 20);
LocalDate expectDate = specailDate.plus(100, ChronoUnit.DAYS);
System.out.println("比较特别的一天" + specailDate);
System.out.println("特殊日期的 100 天" + expectDate);
8. 重复注解
重复注解,即一个注解可以在一个类、属性或者方法上同时使用多次;用 @Repeatable 定义重复注解
@Repeatable(ScheduleTimes.class)
public @interface ScheduleTime {
String value();
}
public @interface ScheduleTimes {
ScheduleTime[] value();
}
public class ScheduleTimeTask {
@ScheduleTime("10")
@ScheduleTime("12")
public void doSomething() { }
}
9. Base64
Java 8 把 Base64 编码的支持加入到官方库中~
String str = "私信资料,领一线大厂面试专题";
String encoded = Base64.getEncoder().encodeToString(str.getBytes( StandardCharsets.UTF_8));
String decoded = new String(Base64.getDecoder().decode(encoded), StandardCharsets.UTF_8);
10. JVM 的新特性
使用元空间 Metaspace 代替持久代(PermGen space),JVM 参数使用-XX:MetaSpaceSize 和-XX:MaxMetaspaceSize 设置大小。
Java 9 新特性
1. java 模块系统
什么是模块化?
?
一个大型系统,比如一个商城网站,它会包含很多模块的,如:订单模块,用户信息模块,商品信息模块,广告位模块等等。各个模块之间会相互调用。如果每个模块单独运行都会带动其他所有模块,性能非常低效。但是,如果某一模块运行时,只会启动它所依赖的模块,性能大大提升。这就是 JDK 9 模块化的思想。
?
什么是 JDK 9 模块化?
?
Java 平台模块系统,即 Project Jigsaw,把模块化开发实践引入到了 Java 平台中。在引入了模块系统之后,JDK 被重新组织成 94 个模块。Java 应用可以通过新增的 jlink 工具,创建出只包含所依赖的 JDK 模块的自定义运行时镜像。这样可以极大的减少 Java 运行时环境的大小。
?
Java 9 模块的重要特征:
?
在其工件(artifact)的根目录中包含了一个描述模块的 module-info.cla
ss 文 件。
工件的格式可以是传统的 JAR 文件或是 Java 9 新增的 JMOD 文件。
这个文件由根目录中的源代码文件 module-info.java 编译而来。
该模块声明文件可以描述模块的不同特征。
?
在 module-info.java 文件中,我们可以用新的关键词 module 来声明一个模块,如下所示。下面给出了一个模块 com.mycompany.mymodule 的最基本的模块声明
module com.jay.sample { //关键词 module 来声明一个模块
exports com.jay.sample; //使用 exports 可以声明模块对其他模块所导出的包。
requires com.jay.common; //使用 requires 可以声明模块对其他模块的依赖关系。
}
2. 不可变集合工厂方法
为了创建不可变集合,JDK9 之前酱紫的:
List<String> stringList = new ArrayList<>();
stringList.add("私信资料:");
stringList.add("领一线大厂面试专题");
List<String> unmodifiableList = Collections.unmodifiableList(stringList);
JDK 9 提供了 List.of()、Set.of()、Map.of()和 Map.ofEntries()等工厂方法来创建不可变集合:
List<String> unmodifiableList = List.of("私信资料:","领一线大厂面试专题");
3. 接口支持私有方法
JDK 8 支持在接口实现默认方法和静态方法,但是不能在接口中创建私有方法,为了避免了代码冗余和提高阅读性,JDK 9 在接口中支持私有方法。
public interface IPrivateInterfaceTest {
//JDK 7 之前
String a = "jay";
void method7();
//JDK 8
default void methodDefault8(){
System.out.println("JDK 8 新特性默认方法");
}
static void methodStatic8() {
System.out.println("JDk 8 新特性静态方法");
}
//Java 9 接口支持私有方法
private void method9(){}
}
4. ?钻石操作符升级
钻石操作符是在 java 7 中引入的,可以让代码更易读,但它不能用于匿名的内部类。
在 java 9 中, 它可以与匿名的内部类一起使用,从而提高代码的可读性。
//JDK 5,6
Map<String, String> map56 = new HashMap<String,String>();
//JDk 7,8
Map<String, String> map78 = new HashMap<>();
//JDK 9 结合匿名内部类的实现
Map<String, String> map9 = new HashMap<>(){};
5. Optional 类改进
java 9 中,java.util.Optional 添加了很多新的有用方法,如:
stream()
ifPresentOrElse()
or()
ifPresentOrElse 方法的改进就是有了 else,接受两个参数 Consumer 和 Runnable。
import java.util.Optional;
public class OptionalTest {
public static void main(String[] args) {
Optional<Integer> optional = Optional.of(1);
optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() ->
System.out.println("Not Present."));
optional = Optional.empty();
optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() ->
System.out.println("Not Present."));
}
}
6. 多版本兼容 Jar 包
?
很多公司使用的 JDK 都是老版本的,JDK6、JDk5 ,甚至 JDk4 的,不是他们不想升级 JDk 版本,而是担心兼容性问题。JDK 9 的一个新特性,多版本兼容 Jar 包解决了这个问题。举个例子:假设你一直用的是小米 8,已经非常习惯它的运行流程了,突然出来小米 9,即使小米 9 很多新功能引人入胜,但是有些人不会轻易买小米 9,因为已经已经习惯小米 8 的流程。同理,为什么很多公司不升级 JDK,就是在此。但是呢,JDK 9 的这个功能很强大,它可以让你的版本升级到 JDK 9,但是还是老版本的运行流程,即在老的运行流程继承新的功能~
?
7. JShell 工具
jShell 工具相当于 cmd 工具,然后呢,你可以像在 cmd 工具操作一样,直接在上面运行 Java 方法,Java 语句等~
jshell> System.out.println("私信资料,领一线大厂面试专题");
私信资料,领一线大厂面试专题
8. try-with-resources 的改进
JDK 9 对 try-with-resources 异常处理机制进行了升级~
//JDK 7,8
try (BufferedReader br = new BufferedReader(new FileReader("d:七里香.txt")) {
br.readLine();
}catch(IOException e){
log.error("IO 异常,e:{}",e);
}
//JDk 9
BufferedReader br = new BufferedReader(new FileReader("d:七里香.txt")
try(br){
br.readLine();
}catch(IOException e){
log.error("IO 异常,e:{}",e);
}
9. Stream API 的改进
JDK 9 为 Stream API 引入以下这些方法,丰富了流处理操作:
takeWhile()
dropWhile()
iterate
ofNullable
「takeWhile」
使用一个断言(Predicate 接口)作为参数,返回给定 Stream 的子集直到断言语句第一次返回 false
// 语法格式
default Stream<T> takeWhile(Predicate<? super T> predicate)
//代码示例
Stream.of(1,2,3).takeWhile(s-> x<2)
.forEach(System.out::println);
//输出
1
「dropWhile」
与 takeWhile()作用相反,使用一个断言(Predicate 接口)作为参数,直到断言语句第一次返回 true,返回给定 Stream 的子集
//语法
default Stream<T> dropWhile(Predicate<? super T> predicate)
//代码示例
Stream.of(1,2,3).dropWhile(s-> x<2)
.forEach(System.out::println);
//输出
2
3
「iterate」
iterate() 方法能够返回以 seed(第一个参数)开头,匹配 Predicate(第二个参数)直到返回 false,并使用第三个参数生成下一个元素的元素流。
//语法
static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
//代码示例
IntStream.iterate(2, x -> x < 10, x -> x*x).forEach(System.out::println);
//输出
2
4
「ofNullable」
如果指定元素为非 null,则获取一个元素并生成单个元素流,元素为 null 则返回一个空 Stream。
//语法
static <T> Stream<T> ofNullable(T t)
//代码示例
Stream<Integer> s1= Stream.ofNullable(100);
s1.forEach(System.out::println)
Stream<Integer> s2 = Stream.ofNullable(null);
s2.forEach(System.out::println)
//输出
100
10.其他
?
HTTP 2 客户端 (支持 WebSocket 和 HTTP2 流以及服务器推送)
进程 API(控制和管理操作系统进程)
String 底层存储结构更改(char[]替换为 byte[])
标识符添加限制( String _ ="hello"不能用)
响应式流 API (支持 Java 9 中的响应式编程)
?
Java 10 新特性
1.局部变量类型推断
JDK 10 增加了局部变量类型推断(Local-Variable Type Inference)功能,让 Java 可以像 Js 里的 var 一样可以自动推断数据类型。Java 中的 var 是一个保留类型名称,而不是关键字。
JDK 10 之前
List<String> list = new ArrayList<String>();
Stream<Integer> stream = Stream.of(1, 2, 3);
JDK 10 之后
var list = new ArrayList<String>(); // ArrayList<String>
var stream = Stream.of(1, 2, 3);
var 变量类型推断的使用也有局限性,仅**「局限」**于以下场景:
具有初始化器的局部变量
增强型 for 循环中的索引变量
传统 for 循环中声明的局部变量
而**「不能用于」**
推断方法的参数类型
构造函数参数类型推断
推断方法返回类型
字段类型推断
捕获表达式
2. 不可变集合的改进
JDK 10 中,List,Set,Map 提供了一个新的静态方法 copyOf(Collection<? extends E> coll),它返回 Collection 集合一个不可修改的副本。
JDK 源码:
static <E> List<E> copyOf(Collection<? extends E> coll) {
return ImmutableCollections.listCopy(coll);
}
使用实例:
var oldList = new ArrayList<String>();
oldList.add("私信资料:");
oldList.add("");
var copyList = List.copyOf(oldList);
oldList.add("收藏、转载、点赞三连");
copyList.add("双击 666"); //UnsupportedOperationException 异常
3. 并行全垃圾回收器 G1
?
JDK 9 引入 G1 作为默认垃圾收集器,执行 GC 时采用的是基于单线程标记扫描压缩算法(mark-sweep-compact)。为了最大限度地减少 Full GC 造成的应用停顿的影响,Java 10 中将为 G1 引入多线程并行 GC,同时会使用与年轻代回收和混合回收相同的并行工作线程数量,从而减少了 Full GC 的发生,以带来更好的性能提升、更大的吞吐量。
?
4. 线程本地握手
Java 10 中线程管控引入 JVM 安全点的概念,将允许在不运行全局 JVM 安全点的情况下实现线程回调,由线程本身或者 JVM 线程来执行,同时保持线程处于阻塞状态,这将会很方便使得停止单个线程或不停止线程成为可能。
5. Optional 新增 orElseThrow()方法
Optional、OptionalDouble 等类新增一个方法 orElseThrow(),在没有值时抛出异常
6. 其他新特性
基于 Java 的 实验性 JIT 编译器
类数据共享
Unicode 语言标签扩展
根证书
基于时间(Time-Based)的版本控制模型
Java 11 新特性
1.字符串操作
String 类是 Java 最常用的类,JDK 11 增加了一系列好用的字符串处理方法
isBlank() 判空。
strip() 去除首尾空格
stripLeading() 去除字符串首部空格
stripTrailing() 去除字符串尾部空格
lines() 分割获取字符串流。
repeat() 复制字符串
// 判断字符串是否为空白
" ".isBlank(); // true
// 去除首尾空格
" jay ".strip(); // "jay"
// 去除首部空格
" jay ".stripLeading(); // "jay "
去除字符串尾部空格
" jay ".stripLeading(); // " jay"
// 行数统计
"a\nb\nc".lines().count(); // 3
// 复制字符串
"jay".repeat(3); // "jayjayjay"
2.用于 Lambda 参数的局部变量语法
局部变量类型推断是 Java 10 引入的新特性,但是不能在 Lambda 表达式中使用。Java 11 再次创新,它允许开发者在 Lambda 表达式中使用 var 进行参数声明。
var map = new HashMap<String, Object>();
map.put("私信资料", "领一线大厂面试专题");
map.forEach((var k, var v) -> {
System.out.println(k + ": " + v);
});
3.标准化 HTTP Client
Java 9 引入 Http Client API,Java 10 对它更新,Java 11 对它进行标准化。这几个版本后,Http Client 几乎被完全重写,支持 HTTP/1.1 和 HTTP/2 ,也支持 websockets。
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://github.com/whx123/JavaHome"))
.GET()
.build();
// 同步
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);
4. 单个命令编译运行源代码
Java 11 增强了 Java 启动器,使之能够运行单一文件的 Java 源代码。
Java 11 之前,要运行一个 Java 源代码必须先编译,再运行
// 编译
javac Jay.java
// 运行
java Jay
Java 11 之后,只要一个 java 命令就搞定
java Jay.java
5. ZGC:可伸缩低延迟垃圾收集器
ZGC ,即 Z Garbage Collector(垃圾收集器或垃圾回收器)。它是一个可伸缩的、低延迟的垃圾收集器。 ZGC 主要为了满足如下目标进行设计:
GC 停顿时间不超过 10ms
既能处理几百 MB 的小堆,也能处理几个 TB 的大堆
应用吞吐能力不会下降超过 15%(与 G1 回收算法相比)
方便在此基础上引入新的 GC 特性和利用 colord
针以及 Load barriers 优化奠定基础
当前只支持 Linux/x64 位平台
6.其他一些特性
添加 Epsilon 垃圾收集器。
支持 TLS 1.3 协议
飞行记录器分析工具
动态类文件常量
低开销的 Heap Profiling
Java 12 新特性
1. Switch 表达式扩展(预览功能)
传统的 switch 语句,容易漏写 break 而出错,同时写法并不简洁优雅。
Java 12 之前
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;
}
JDk 12 之后,Switch 表达式得到增强,能接受语句和表达式。
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);
}
2. 紧凑的数据格式
JDK 12 新增了 NumberFormat 对复杂数字的格式化
NumberFormat numberFormat = NumberFormat.getCompactNumberInstance(Locale.CHINA, NumberFormat.Style.SHORT);
System.out.println(numberFormat.format(100000));
//output
10 万
3. 字符串支持 transform、indent 操作
transform 字符串转换,可以配合函数式接口 Function 一起使用
List<String> list1 = List.of("jay", " 私信资料,领一线大厂面试专题");
List<String> list2 = new ArrayList<>();
list1.forEach(element ->
list2.add(element.transform(String::strip)
.transform((e) -> "Hello," + e))
);
list2.forEach(System.out::println);
//输出
Hello,jay
Hello,私信资料,领一线大厂面试专题
indent 缩进,每行开头增加空格 space 和移除空格
String result = "Java\n Python\nC".indent(3);
System.out.println(result);
//输出
Java
Python
C
4. Files.mismatch(Path, Path)
Java 12 新增了 mismatch 方法,此方法返回第一个不匹配的位置,如果没有不匹配,则返回 -1L。
public static long mismatch(Path path, Path path2) throws IOException;
代码示例:
Path file1 = Paths.get("c:\jay.txt");
Path file2 = Paths.get("c:\私信资料领一线大厂面试专题.txt");
try {
long fileMismatch = Files.mismatch(file1, file2);
System.out.println(fileMismatch);
} catch (IOException e) {
e.printStackTrace();
}
5. Teeing Collector
Teeing Collector 是 Streams API 中引入的新的收集器实用程序,它的作用是 merge 两个 collector 的结果,API 格式如下:
public static <T, R1, R2, R>
Collector<T, ?, R> teeing(Collector<? super T, ?, R1> downstream1,
Collector<? super T, ?, R2> downstream2,
BiFunction<? super R1, ? super R2, R> merger)
直接看代码例子吧,如下为求学生的平均分和总分的例子
List<Student> studentList= Arrays.asList(
new Student("jay", 90),
new Student("私信资料,领一线大厂面试专题", 100),
new Student("私信资料,领一线大厂面试专题", 80)
);
String teeingResult=studentList.stream().collect(
Collectors.teeing(
Collectors.averagingInt(Student::getScore),
Collectors.summingInt(Student::getScore),
(s1,s2)-> s1+ ":"+ s2
)
);
System.out.println(teeingResult); //90:270
6.其他特性
支持 unicode 11(684 个新字符、11 个新 blocks、7 个新脚本)
JVM 常量 API (主要在新的 java.lang.invoke.constant 包中定义了一系列基于值的符号引用类型,能够描述每种可加载常量。)
Shenandoah GC(低暂停时间垃圾收集器)
G1 收集器提升 (可中止的混合收集集合、及时返回未使用的已分配内存)
默认 CDS 档案
JMH 基准测试
Java 13 新特性
Switch 表达式扩展(引入 yield 关键字)
传统的 switch:
private static String getText(int number) {
String result = "";
switch (number) {
case 1, 2:
result = "one or two";
break;
case 3:
result = "three";
break;
case 4, 5, 6:
result = "four or five or six";
break;
default:
result = "unknown";
break;
Java 13 之后,value break 语句不再被编译,而是用 yield 来进行值返回
private static String getText(int number) {
return switch (number) {
case 1, 2:
yield "one or two";
case 3:
yield "three";
case 4, 5, 6:
yield "four or five or six";
default:
yield "unknown";
};
}
2.文本块升级
Java 13 之前,字符串不能够多行使用,需要通过换行转义或者换行连接符等等,反正就是好麻烦、好难维护。
String html = "<html>\n" +
" <body>\n" +
" <p>Hello, 私信资料,领一线大厂面试专题</p>\n" +
" </body>\n" +
"</html>\n";
Java 13 之后,清爽多了~
String html = """
<html>
<body>
<p>Hello, 私信资料,领一线大厂面试专题</p>
</body>
</html>
""";
3. SocketAPI 重构
传统的 Java Socket API(java.net.ServerSocket 和 java.net.Socket)依赖于 SocketImpl 的内部实现
在 Java 13 之前,通过使用 PlainSocketImpl 作为 SocketImpl 的具体实现。
Java 13 中的新底层实现,引入 NioSocketImpl 的实现用以替换 SocketImpl 的 PlainSocketImpl 实现,此实现与 NIO(新 I/O)实现共享相同的内部基础结构,并且与现有的缓冲区高速缓存机制集成在一起。
一个 Socket 简单例子:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketAPITest {
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(8080)){
boolean runFlag = true;
while(runFlag){
Socket clientSocket = serverSocket.accept();
//搞事情
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行以上的实例,看下是否有以下关键词输出~
[class,load] sun.nio.ch.NioSocketImpl
4.FileSystems.newFileSystem 新方法
FileSystems 类中添加了以下三种新方法,以便更容易地使用将文件内容视为文件系统的文件系统提供程序:
1、newFileSystem(Path)
2、newFileSystem(Path, Map<String, ?>)
3、newFileSystem(Path, Map<String, ?>, ClassLoader)
5. 增强 ZGC 释放未使用内存
ZGC 是 Java 11 中引入的最为瞩目的垃圾回收特性,是一种可伸缩、低延迟的垃圾收集器。但是实际使用中,它不能够主动将未使用的内存释放给操作系统。
评论