New Java Feature - Flow
指令式编程
最常用的代码控制模式
1System.out.println("Hello, World!");
通过代码发布指令,然后等待指令的执行以及指令执行带来的状态变化
并且根据目前的状态,来确定下一次要发布的指令,并且用代码把下一个指令表示出来
指令式编程模型关注的重点在于控制状态
1234567try { Digest messageDigest = Digest.of("SHA-256"); byte[] digestValue = messageDigest.digest("Hello, world!".getBytes());} catch (NoSuchAlgorithmException ex) { System.out.println("Unsupported algorithm: SHA-256");}
首先调用 Digest.of 方法,得到一个 Digest 实例
然后调用该实例的方法 Digest.dig ...
New Java Feature - Error Code
概述
Java 的异常处理是对代码性能有着重要影响的因素
Java 的异常处理,有着天生优势,特别是在错误排查方面的作用,很难找到合适的替代方案
用例123456789101112131415161718192021222324252627282930313233343536package me.zhongmingmao;import java.security.NoSuchAlgorithmException;public class UseCase { public static void main(String[] args) { String[] algorithms = {"SHA-128", "SHA-192"}; String availableAlgorithm = null; for (String algorithm : algorithms) { Digest md; try { md = Digest.of(algorithm) ...
New Java Feature - Exception
概述
Java 异常的使用和处理,是滥用最严重,诟病最多,也是最难平衡的一个难题
Java 语言支持三种异常的状况
非正常异常(Error)、运行时异常(Runtime Exception)、检查型异常(Checked Exception)
异常,除非特别声明,一般指的是 Checked Exception 和 Checked Exception
异常状况的处理会让代码的效率变低 - 不应该使用异常机制来处理正常情况
理想情况下,在执行代码时没有任何异常发生,否则业务执行的效率会大打折扣
几乎无法完成,不管是 JDK 核心类库还是业务代码,都存在大量的异常处理代码
软件都是由很多类库集成的,大部分类库,都只是从自身的角度去考虑问题,使用异常来处理问题
很难期望业务执行下来没有任何异常发生
抛出异常影响了代码的运行效率,而实际业务又没有办法完全不抛出异常
新的编程语言(Go),彻底抛弃类似于 Java 这样的异常机制,重新拥抱 C 语言的错误方式
性能
没有抛出异常的用例,能够支持的吞吐量要比抛出异常的用例大 1000 倍
案例
在设计算法公开接口时,算法的敏捷性是必须要要考虑的问题
...
New Java Feature - Switch Matching
案例
假设上面表示形状的封闭类和许可类是版本 1.0,它们被封装在一个基础 API 类库里 - 基础类库
而 isSquare 的实现代码,被封装在另一个 API 类库里 - 扩展类库
新加入一个许可类,用来表示长方形 - 基础类库的升级,扩展类库也要同步升级 - 但不一定能意识到
对于需要更改扩展类库这件事,基础类库的作者,不会通知到扩展类库的作者
一般情况下,基础类库和扩展类库是独立的作品,由不同的团队和社区维护
基础类库的作者不太可能意识到扩展类库的存在,更不可能去研究扩展类库的实现细节
扩展类库维护者也不会注意到基础类库的修改,更不容易想到基础类库的修改会影响到扩展类库的行为
模式匹配的 switch
具有模式匹配能力的 switch - 将模式匹配扩展到 switch 语句和 switch 表达式
允许测试多个模式,每个模式多可以有特定的操作 - 简洁安全地表达复杂的面向数据的查询
扩充的匹配类型
在 JDK 17 之前的 switch 关键字可以匹配的数据类型包括 - 数字、枚举和字符串 - 本质上都是整型的原始类型
在 JDK 17 之后,匹配的目标数据类型,可以是一个 ...
New Java Feature - Switch Expression
概述
JDK 14
在 Java 规范里,表达式完成对数据的操作
一个表达式的结果可以是一个数值(i * 4);或者是一个变量(i = 4);或者什么都不是(void 类型)
Java 语句是 Java 最基本的可执行单元
它本身不是一个数值,也不是一个变量
Java 语句的标志性符号是分号(代码)和大括号(代码块) - if-else 语句、赋值语句等
switch 表达式是一个表达式,而 switch 语句是一个语句
Switch 语句12345678910111213141516171819202122232425262728293031323334353637class DaysInMonth { public static void main(String[] args) { Calendar today = Calendar.getInstance(); int month = today.get(Calendar.MONTH); int year = today.get(Calendar.YEAR); int daysInMo ...
New Java Feature - Pattern Matching
概述
Java 模式匹配是一个新型的、而且还在持续快速演进的领域
类型匹配是模式匹配的一个规范,在 JDK 16 正式发布
一个模式是匹配谓词和匹配变量的组合
匹配谓词用来确定模式和目标是否匹配
在模式和目标匹配的情况下,匹配变量是从匹配目标里提取出来的一个或者多个变量
对于类型匹配来说,匹配谓词用来指定模式的数据类型,而匹配变量就是属于该类型的数据变量
对于类型匹配来说,匹配变量只有一个
模式12345678static boolean isSquare(Shape shape) { if (shape instanceof Rectangle) { Rectangle rect = (Rectangle) shape; return (rect.length == rect.width); } return (shape instanceof Square);}
模式拆分 - 类型判断 + 类型转换 - 增加出错概率
类型判断语句 - 匹配谓词
类型转换语句
声明一个新的本地变量,即匹配变量,来承载 ...
New Java Feature - Sealed
无法穷举
判断一个形状是不是正方形
上述判断 - 一个形状的对象是不是一个正方形的实例
一个形状的对象即使不是一个正方形的实例,也可能是一个正方形
很多形状的特殊形式就是正方形 - 长方形、菱形、梯形、多边形等 - 无法穷举
通过 instanceof 并不能正确判断一个形状是否为正方形
问题根源 - 无限制的扩展性
限制扩展性
OOP 的最佳实践之一,就是把可扩展性限制在可以预测和控制的范围内,而不是无限的扩展性
继承的安全缺陷
一个可扩展的类,子类和父类可能会相互影响,从而导致不可预知的行为
涉及敏感信息的类,增加可扩展性不一定是个优先选项,要尽量避免父类或者子类的影响
在设计 API 时,需要反复思考
一个类,有没有真实的可扩展需求,能不能使用 final 修饰符
一个方法,子类有没有重写的必要性,能不能使用 final 修饰符
限制住不可预测的可扩展性,是实现安全代码、健壮代码的一个重要目标
在 JDK 17 之前,限制可扩展性只有两个方法 - 使用私有类或者 final 修饰符
私有类不是公开接口,只能内部使用,而 final 修饰符则彻底放弃了可扩展性
要么全开放,要 ...
New Java Feature - Record
概述
JDK 16
Java 档案类是用来表示不可变数据的透明载体
OOP
封装 + 继承 + 多态
接口不是多线程安全的 - 将 Public 方法设置成同步方法 - 开销很大
更优方案 - 即使不使用线程同步,也能做到多线程安全 - 不可变对象
天生的多线程安全 - 类对象一旦实例化就不能再修改
简化代码 - 删除读取半径的方法,直接公开半径这个变量 - 与 Go 类似
Circle 一直可以用半径来表达,所以并没有带来违反封装原则的实质性后果
进一步简化
使用公开的只读变量 - 使用 final 修饰符来表明只读变量
公开的只读变量,只在在公开的构造方法中赋值 - 解决对象的初始化问题
公开的只读变量,替换掉了读取的方法 - 减少代码量
声明档案类
Java 档案类是用来表示不可变数据的透明载体
record 关键字是 class 关键字的一种特殊表现形式,用来标识档案类
record 关键字可以使用与 class 关键字差不多一样的类修饰符 - public/static
类标识符 Circle 后,用小括号括起来的参数 - 类似于一个构造方法
...
New Java Feature - Text Blocks
概述
JDK 15
文字块 - 一个由多行文字构成的字符串
复杂字符串
需要处理 - 文本对齐、换行字符、连接符以及双引号的转义字符串 - 不美观 + 不简约 + 不自然
1234567String stringBlock = "<!DOCTYPE html>\n" + "<html>\n" + " <body>\n" + " <h1>\"Hello World!\"</h1>\n" + " </body>\n" + "</html>\n";
所见即所得的文字块
文字块是一个由多行文件构成的字符串
文字块使用新的形式,尝试消除换行符、连接符、转义字符的影响
使得文字对齐和必要的占位符更加清晰,从而简化多行文字字符串的表达
换行符 \n 没有出现在文字块这个
连字符 + ...
New Java Feature - JShell
概述
JDK 9
JShell 是 Java 的交互式编程环境
JShell API 和工具提供了一种在 JShell 状态下评估 Java 编程语言的声明、语句和表达式的方式
JShell 的状态包括不断发展的代码和执行状态
为了便于快速调查和编码
语句和表达式不需要出现在方法中
变量和方法也不需要出现在类中
启动 JShell12345$ jshell| Welcome to JShell -- Version 21.0.7| For an introduction type: /help introjshell>
详尽模式
12345$ jshell -v| Welcome to JShell -- Version 21.0.7| For an introduction type: /help introjshell>
退出 JShell123456$ jshell -v| Welcome to JShell -- Version 21.0.7| For an introduction type: /help introjshell> /exit| Go ...