New Java Feature - Foreign Function API
概述 Java 的外部函数接口这个特性,与外部内存接口一起,会极大地丰富 Java 语言的生态环境 像 Java 或者 Go 这样的通用编程语言,都需要和其它的编程语言或者环境打交道 - 如操作系统或者 C 语言 Java 通过 Java 本地接口 JNI 来支持该做法 本地方法接口示例1234567891011public class HelloWorld { static { System.loadLibrary("helloWorld"); } public static void main(String[] args) { new HelloWorld().sayHello(); } private native void sayHello();} sayHello 使用了 native 修饰符,是一个本地方法,可以使用 C 语言实现 - 生成对应的 C 语言的头文件 1234$ javac -h . HelloWorld.java$ lsHe...
New Java Feature - Foreign Memory API
概述 在讨论代码性能的时候,内存的使用效率是一个绕不开的话题 - Flink/Netty 为了避免 JVM GC 不可预测的行为以及额外的性能开销,一般倾向于使用 JVM 之外的内存来存储和管理数据 - 堆外数据 - off-heap data 使用堆外存储最常用的办法,是使用 ByteBuffer 来分配直接存储空间 - direct buffer JVM 会尽最大努力直接在 direct buffer 上执行 IO 操作,避免数据在本地和 JVM 之间的拷贝 频繁的内存拷贝是性能的主要障碍之一 为了极致的性能,应用程序通常会尽量避免内存的拷贝 理想的情况下,一份数据只需要一份内存空间 - 即零拷贝 ByteBuffer 使用 ByteBuffer 来分配直接存储空间 1public static ByteBuffer allocateDirect(int capacity); ByteBuffer 所在的 Java 包是 java.nio,ByteBuffer 的设计初衷是用于非阻塞编程 ByteBuffer 是异步编程和非阻塞编程的核心类,几乎所有的 Java 异步模...
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....
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(algorit...
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 daysI...
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 后,用小括号括起来的参数 - 类似于一个构造...















