Java 教程
- Java - 首页
- Java - 概述
- Java - 历史
- Java - 特性
- Java 与 C++
- JVM - Java 虚拟机
- Java - JDK vs JRE vs JVM
- Java - Hello World 程序
- Java - 环境搭建
- Java - 基本语法
- Java - 变量类型
- Java - 数据类型
- Java - 类型转换
- Java - Unicode 系统
- Java - 基本运算符
- Java - 注释
- Java - 用户输入
- Java - 日期和时间
Java 控制语句
- Java - 循环控制
- Java - 决策制定
- Java - If-else
- Java - Switch
- Java - For 循环
- Java - For-Each 循环
- Java - While 循环
- Java - do-while 循环
- Java - Break
- Java - Continue
面向对象编程
- Java - OOPs 概念
- Java - 对象和类
- Java - 类属性
- Java - 类方法
- Java - 方法
- Java - 变量作用域
- Java - 构造函数
- Java - 访问修饰符
- Java - 继承
- Java - 聚合
- Java - 多态
- Java - 重写
- Java - 方法重载
- Java - 动态绑定
- Java - 静态绑定
- Java - 实例初始化块
- Java - 抽象
- Java - 封装
- Java - 接口
- Java - 包
- Java - 内部类
- Java - 静态类
- Java - 匿名类
- Java - 单例类
- Java - 包装类
- Java - 枚举
- Java - 枚举构造函数
- Java - 枚举字符串
Java 内置类
Java 文件处理
Java 错误和异常
- Java - 异常
- Java - try-catch 块
- Java - try-with-resources
- Java - 多重捕获块
- Java - 嵌套 try 块
- Java - Finally 块
- Java - throw 异常
- Java - 异常传播
- Java - 内置异常
- Java - 自定义异常
Java 多线程
- Java - 多线程
- Java - 线程生命周期
- Java - 创建线程
- Java - 启动线程
- Java - 线程合并
- Java - 线程命名
- Java - 线程调度器
- Java - 线程池
- Java - 主线程
- Java - 线程优先级
- Java - 守护线程
- Java - 线程组
- Java - 关闭钩子
Java 同步
Java 网络
- Java - 网络
- Java - 套接字编程
- Java - URL 处理
- Java - URL 类
- Java - URLConnection 类
- Java - HttpURLConnection 类
- Java - Socket 类
- Java - 泛型
Java 集合
Java 接口
Java 数据结构
Java 集合算法
高级 Java
- Java - 命令行参数
- Java - Lambda 表达式
- Java - 发送邮件
- Java - Applet 基础
- Java - Javadoc 注释
- Java - 自动装箱和拆箱
- Java - 文件不匹配方法
- Java - REPL (JShell)
- Java - 多版本 Jar 文件
- Java - 私有接口方法
- Java - 内部类菱形运算符
- Java - 多分辨率图像 API
- Java - 集合工厂方法
- Java - 模块系统
- Java - Nashorn JavaScript
- Java - Optional 类
- Java - 方法引用
- Java - 函数式接口
- Java - 默认方法
- Java - Base64 编码解码
- Java - Switch 表达式
- Java - Teeing 收集器
- Java - 微基准测试
- Java - 文本块
- Java - 动态 CDS 归档
- Java - Z 垃圾收集器 (ZGC)
- Java - 空指针异常
- Java - 打包工具
- Java - 密封类
- Java - 记录类
- Java - 隐藏类
- Java - 模式匹配
- Java - 紧凑数字格式化
- Java - 垃圾回收
- Java - JIT 编译器
Java 杂项
- Java - 递归
- Java - 正则表达式
- Java - 序列化
- Java - 字符串
- Java - Process API 改进
- Java - Stream API 改进
- Java - 增强的 @Deprecated 注解
- Java - CompletableFuture API 改进
- Java - 流
- Java - 日期时间 Api
- Java 8 - 新特性
- Java 9 - 新特性
- Java 10 - 新特性
- Java 11 - 新特性
- Java 12 - 新特性
- Java 13 - 新特性
- Java 14 - 新特性
- Java 15 - 新特性
- Java 16 - 新特性
Java API 和框架
Java 类参考
- Java - Scanner
- Java - 数组
- Java - 字符串
- Java - Date
- Java - ArrayList
- Java - Vector
- Java - Stack
- Java - PriorityQueue
- Java - LinkedList
- Java - ArrayDeque
- Java - HashMap
- Java - LinkedHashMap
- Java - WeakHashMap
- Java - EnumMap
- Java - TreeMap
- Java - IdentityHashMap
- Java - HashSet
- Java - EnumSet
- Java - LinkedHashSet
- Java - TreeSet
- Java - BitSet
- Java - Dictionary
- Java - Hashtable
- Java - Properties
- Java - Collection
- Java - Array
Java 有用资源
Java 9 - 新特性
JAVA 9(也称为 jdk 1.9)是JAVA 编程语言开发的一个主要版本。其初始版本于 2017 年 9 月 21 日发布。Java 9 版本的主要目标是:
使 JDK 和 Java 标准版平台基于模块化,这意味着它可以缩减到小型计算设备。
提高 JDK 和 Java 实现的整体安全性。
使 Java 代码库和大型应用程序的构建过程和维护对于 JAVA SE 和 EE 平台来说更容易。
为 Java 平台设计和实现一个标准的模块系统,该系统可以轻松地应用于平台和 JDK。
以下是 Java 9 支持的新特性列表
模块系统
模块系统旨在将 Java 代码中的模块化提升到一个新的水平。模块是代码和数据的自描述集合。模块可以包含包,以及特定于特定功能的配置。模块提供了对自身内容的更好的访问控制。从 Java 9 开始,Java 库被分成多个模块,可以使用以下命令查看。
C:\Users\Mahesh>java --list-modules [email protected] [email protected] [email protected] [email protected] ... [email protected] [email protected]
示例 - 使用模块
以下代码片段定义了一个在应用程序根文件夹中的 module-info.java 文件中声明的模块。
module com.tutorialspoint.greetings { requires com.tutorialspoint.util; requires static com.tutorialspoint.logging; requires transitive com.tutorialspoint.base; exports com.tutorialspoint.greetings.HelloWorld; opens com.tutorialspoint.greetings.HelloWorld; }
在这里,我们声明了我们的模块依赖于三个模块,并导出了一个供外部世界使用的公共类,并允许反射检查特定类。默认情况下,模块的私有成员无法通过反射访问。
REPL
REPL 代表 读取-求值-打印-循环。Java 9 中引入了一个 REPL 引擎JShell,它是一个交互式控制台,用于在控制台中运行任意 Java 代码片段,无需保存和编译 Java 代码文件。JShell 读取输入的每一行,对其求值,然后打印结果,然后再次准备接收下一组输入。
示例 - 使用 JShell 作为 REPL
以下代码片段展示了如何在 JShell 中创建变量。分号是可选的。我们也可以在 JShell 中创建对象。如果变量未初始化,则会赋予默认值,如果是对象引用则为 null。创建变量后,就可以使用它,如最后一个语句所示,我们使用了字符串变量来打印其值。
示例
在以下示例中,我们创建了变量,求值表达式,创建了日期对象。
jshell> int i = 10 i ==> 10 jshell> String name = "Mahesh"; name ==> "Mahesh" jshell> Date date = new Date() date ==> Fri Feb 02 14:52:49 IST 2024 jshell> String.format("%d pages read.", 10); $9 ==> "10 pages read." jshell> $9 $9 ==> "10 pages read." jshell> name name ==> "Mahesh"
改进的 JavaDocs
从 Java 9 开始,Java 现在支持 HTML5 输出生成,并在生成的 API 文档中提供搜索框。
示例
在这个例子中,我们正在创建一个兼容 HTML5 的 javadoc。
考虑 C:/JAVA 文件夹中的以下代码。
Tester.java
/** * @author MahKumar * @version 0.1 */ public class Tester { /** * Default method to be run to print * <p>Hello world</p> * @param args command line arguments */ public static void main(String []args) { System.out.println("Hello World"); } }
运行 jdk 9 的 javadoc 工具,并使用 -html5 标志生成新的文档类型。
C:\JAVA> javadoc -d C:/JAVA -html5 Tester.java Loading source file Tester.java... Constructing Javadoc information... Standard Doclet version 9.0.1 Building tree for all the packages and classes... Generating C:\JAVA\Tester.html... Generating C:\JAVA\package-frame.html... Generating C:\JAVA\package-summary.html... Generating C:\JAVA\package-tree.html... Generating C:\JAVA\constant-values.html... Building index for all the packages and classes... Generating C:\JAVA\overview-tree.html... Generating C:\JAVA\index-all.html... Generating C:\JAVA\deprecated-list.html... Building index for all classes... Generating C:\JAVA\allclasses-frame.html... Generating C:\JAVA\allclasses-frame.html... Generating C:\JAVA\allclasses-noframe.html... Generating C:\JAVA\allclasses-noframe.html... Generating C:\JAVA\index.html... Generating C:\JAVA\help-doc.html...
它将在 D:/test 目录中创建更新的 Java 文档页面,您将看到以下输出。
多版本 JAR
Java 9 中的多版本 JAR 功能增强了 JAR 格式,以便多个特定于 Java 版本的类文件可以共存于单个归档文件中。
在多版本 Jar 格式中,一个 jar 文件可以包含不同版本的 Java 类或资源,可以根据平台进行维护和使用。在 JAR 中,文件 MANIFEST.MF 文件在其主部分中有一个条目 Multi-Release: true。META-INF 目录还包含一个 versions 子目录,其子目录(从 Java 9 开始以 9 开头)存储特定于版本的类和资源文件。
使用 MANIFEST.MF,我们可以指定 Java 9 或更高版本特定类的单独位置,如下所示:
Java 多版本 Jar 文件目录结构示例
jar root - Calculator.class - Util.class - Math.class - Service.class META-INF - versions - 9 - Util.class - Math.class - 10 - Util.class - Math.class
现在,如果 JRE 不支持多版本 jar,则它将选择根级别的类来加载和执行,否则,将加载特定于版本的类。例如,如果上述 jar 用于 Java 8,则将使用根级别的 Util.class。如果相同的 jar 由 Java 9 执行,则将选择 Java 9 版本的特定类,依此类推。这样,第三方库/框架可以在不更改其针对较低版本编写的源代码的情况下支持新功能。
集合工厂方法改进
在 Java 9 中,为 List、Set 和 Map 接口添加了新的静态工厂方法,以创建这些集合的不变实例。这些工厂方法主要是为了以更简洁的方式创建集合的便利工厂方法。
Java 9 之前 List 接口工厂方法的示例
在这里,我们正在创建 Java 9 之前不可修改的列表。
package com.tutorialspoint; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Tester { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("Java"); list.add("HTML 5"); list.add("C"); list = Collections.unmodifiableList(list); System.out.println(list); } }
让我们编译并运行上述程序,这将产生以下结果:
[Java, HTML 5, C]
Java 9 中 List 接口工厂方法的示例
在这里,我们正在创建 Java 9 中不可修改的列表。
package com.tutorialspoint; import java.util.List; public class Tester { public static void main(String[] args){ List<String> list = List.of("Java","HTML 5","C"); System.out.println(list); } }
让我们编译并运行上述程序,这将产生以下结果:
[Java, HTML 5, C]
私有接口方法
Java 9 引入了私有和静态私有接口方法。作为私有方法,此类方法无法通过实现类或子接口访问。引入这些方法是为了允许封装,其中某些方法的实现将仅保留在接口中。这有助于减少重复性,提高可维护性和编写整洁的代码。
示例 - Java 9 中接口中的私有方法
package com.tutorialspoint; interface util { public default int operate(int a, int b) { return sum(a, b); } private int sum(int a, int b) { return a + b; } } public class Tester implements util { public static void main(String[] args) { Tester tester = new Tester(); System.out.println(tester.operate(2, 3)); } }
输出
让我们编译并运行上述程序,这将产生以下结果:
5
类似地,我们可以拥有私有静态方法,该方法可以从静态和非静态方法中调用。
进程 API 改进
在 Java 9 中,负责控制和管理操作系统进程的 Process API 已经得到了相当大的改进。ProcessHandle 类现在提供了进程的原生进程 ID、启动时间、累积 CPU 时间、参数、命令、用户、父进程和子进程。ProcessHandle 类还提供方法来检查进程的活动状态并销毁进程。它具有 onExit 方法,CompletableFuture 类可以在进程退出时异步执行操作。
生成新进程示例
在此示例中,我们为记事本创建了一个新进程,并使用 ProcessBuilder 启动它。使用 ProcessHandle.Info 接口,我们获取新生成的进程的进程信息。
package com.tutorialspoint; import java.time.ZoneId; import java.util.stream.Stream; import java.util.stream.Collectors; import java.io.IOException; public class Tester { public static void main(String[] args) throws IOException { ProcessBuilder pb = new ProcessBuilder("notepad.exe"); String np = "Not Present"; Process p = pb.start(); ProcessHandle.Info info = p.info(); System.out.printf("Process ID : %s%n", p.pid()); System.out.printf("Command name : %s%n", info.command().orElse(np)); System.out.printf("Command line : %s%n", info.commandLine().orElse(np)); System.out.printf("Start time: %s%n", info.startInstant().map(i -> i.atZone(ZoneId.systemDefault()) .toLocalDateTime().toString()).orElse(np)); System.out.printf("Arguments : %s%n", info.arguments().map(a -> Stream.of(a).collect( Collectors.joining(" "))).orElse(np)); System.out.printf("User : %s%n", info.user().orElse(np)); } }
输出
您将看到类似的输出。
Process ID : 5580 Command name : C:\Program Files\WindowsApps\Microsoft.WindowsNotepad_11.2401.26.0_x64__8wekyb3d8bbwe\Notepad\Notepad.exe Command line : Not Present Start time: 2024-04-02T17:07:14.305 Arguments : Not Present User : DESKTOP\Tutorialspoint
Stream API 改进
Stream 在 Java 8 中引入,以帮助开发人员从对象序列执行聚合操作。在 Java 9 中,添加了一些方法来改进 Stream。
takeWhile(Predicate 接口) 方法
语法
default Stream<T> takeWhile(Predicate<? super T> predicate)
takeWhile 方法获取所有值,直到谓词返回 false。在有序流的情况下,它返回一个流,该流包含从该流中获取的与给定谓词匹配的最长前缀元素。
dropWhile(Predicate 接口)
语法
default Stream<T> dropWhile(Predicate<? super T> predicate)
dropWhile 方法丢弃开头所有值,直到谓词返回 true。在有序流的情况下,它返回一个流,该流包含在丢弃与给定谓词匹配的最长前缀元素后该流的剩余元素。
iterate 方法
语法
static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
iterate 方法现在具有 hasNext 谓词作为参数,一旦 hasNext 谓词返回 false,循环就会停止。
ofNullable
语法
static <T> Stream<T> ofNullable(T t)
引入 ofNullable 方法是为了防止 NullPointerExceptions 并避免 Stream 的空检查。此方法返回一个包含单个元素的顺序 Stream(如果非空),否则返回一个空 Stream。
带资源的 try 改进
在 Java 9 之前,资源需要在 try 之前或 try 语句内声明,如下面的示例所示。在此示例中,我们将使用 BufferedReader 作为资源来读取字符串,然后关闭 BufferedReader。
Java 9 及更高版本
import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; import java.io.StringReader; public class Tester { public static void main(String[] args) throws IOException { System.out.println(readData("test")); } static String readData(String message) throws IOException { Reader inputString = new StringReader(message); BufferedReader br = new BufferedReader(inputString); try (br) { return br.readLine(); } } }
输出
让我们编译并运行上述程序,这将产生以下结果:
test
增强的 @Deprecated 注解
@Deprecated 注解是在 Java 5 版本中引入的。使用 @Deprecated 注解的程序元素意味着出于以下任何原因都不应使用它:
- 其使用可能会导致错误。
- 它可能在未来版本中不兼容。
- 它可能在未来版本中被删除。
- 更好的、更高效的替代方案已取代它。
每当使用已弃用的元素时,编译器都会生成警告。在 Java 9 中,对 @Deprecated 注解进行了两项新的增强。
forRemoval - 指示被注解的元素是否将在未来版本中被移除。默认值为 false。
since - 返回被注解的元素何时被弃用的版本。默认值为空字符串。
使用 since 弃用
以下 Java 9 上 Boolean 类的 javadoc 示例说明了在 @Deprecated 注解上使用 since 属性。
使用 forRemoval 弃用
以下 Java 9 上 System 类的 javadoc 示例说明了在 @Deprecated 注解上使用 forRemoval 属性。
内部类菱形运算符
在 Java 9 中,菱形运算符也可以与匿名类一起使用,以简化代码并提高可读性。
示例
在下面的示例中,我们为抽象类 Handler 创建了匿名类,该类接受泛型参数,但在创建匿名类时没有对象类型,因为我们不需要传递类型参数。编译器本身会推断类型。
public class Tester { public static void main(String[] args) { // create an Anonymous class to handle 1 // Here we do not need to pass Type arguments in diamond operator // as Java 9 compiler can infer the type automatically Handler<Integer> intHandler = new Handler<>(1) { @Override public void handle() { System.out.println(content); } }; intHandler.handle(); Handler<? extends Number> intHandler1 = new Handler<>(2) { @Override public void handle() { System.out.println(content); } }; intHandler1.handle(); Handler<?> handler = new Handler<>("test") { @Override public void handle() { System.out.println(content); } }; handler.handle(); } } abstract class Handler<T> { public T content; public Handler(T content) { this.content = content; } abstract void handle(); }
输出
让我们编译并运行上述程序,这将产生以下结果:
1 2 Test
多分辨率图像 API
多分辨率图像 API 是在 Java 9 中引入的。此 API 支持具有不同分辨率变体的多个图像。此 API 允许将一组具有不同分辨率的图像用作单个多分辨率图像。
考虑以下图像。
这些是三个不同尺寸的徽标图像。
现在,为了使用这三个图像,从 Java 9 开始,可以使用多分辨率图像 API 作为单个 API 来获取所有变体或要显示的特定变体。
// read all images into one multiresolution image MultiResolutionImage multiResolutionImage = new BaseMultiResolutionImage(images.toArray(new Image[0]));
这里 MultiResolutionImage 和 BaseMultiResolutionImage 类是 java.awt.image 包的一部分。
以下是多分辨率图像的主要操作。
Image getResolutionVariant(double destImageWidth, double destImageHeight) - 获取最适合在指定尺寸下表示此逻辑图像的特定图像。
List<Image> getResolutionVariants() - 获取所有分辨率变体的可读列表。
示例 - 获取所有变体
在此示例中,我们加载了三个图像并将它们存储在 MultiResolutionImage 中。然后使用 getResolutionVariants() 方法,我们检查此多分辨率图像中所有可用的图像变体并打印它。
package com.tutorialspoint; import java.awt.Image; import java.awt.image.BaseMultiResolutionImage; import java.awt.image.MultiResolutionImage; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import javax.imageio.ImageIO; public class Tester { public static void main(String[] args) throws IOException, MalformedURLException { // prepare a list of urls of all images List<String> imgUrls = List.of("https://tutorialspoint.com/java9/images/logo.png", "https://tutorialspoint.com/java9/images/mini_logo.png", "https://tutorialspoint.com/java9/images/large_logo.png"); // create a list of Image object List<Image> images = new ArrayList<Image>(); // Create image objects using image urls for (String url : imgUrls) { images.add(ImageIO.read(new URL(url))); } // read all images into one multiresolution image MultiResolutionImage multiResolutionImage = new BaseMultiResolutionImage(images.toArray(new Image[0])); // get all variants of images List<Image> variants = multiResolutionImage.getResolutionVariants(); System.out.println("Total number of images: " + variants.size()); // print all the images for (Image img : variants) { System.out.println(img); } } }
输出
让我们编译并运行上述程序,这将产生以下结果:
Total number of images: 3 BufferedImage@7ce6a65d: type = 6 ColorModel: #pixelBits = 32 numComponents = 4 color space =java.awt.color.ICC_ColorSpace@548ad73b transparency = 3 has alpha = true isAlphaPre = false ByteInterleavedRaster: width =311 height = 89 #numDataElements 4 dataOff[0] = 3 BufferedImage@4c762604: type = 6 ColorModel: #pixelBits = 32 numComponents = 4 color space =java.awt.color.ICC_ColorSpace@548ad73b transparency = 3 has alpha = true isAlphaPre = false ByteInterleavedRaster: width =156 height = 45 #numDataElements 4 dataOff[0] = 3 BufferedImage@2641e737: type = 6 ColorModel: #pixelBits = 32 numComponents = 4 color space =java.awt.color.ICC_ColorSpace@548ad73b transparency = 3 has alpha = true isAlphaPre = false ByteInterleavedRaster: width =622 height = 178 #numDataElements 4 dataOff[0] = 3
CompletableFuture API 增强
CompletableFuture 类是在 Java 8 中引入的,用于表示 Future,可以通过显式设置其值和状态来完成它。它可以用作 java.util.concurrent.CompletionStage。它支持依赖函数和操作,这些函数和操作会在 Future 完成时触发。在 Java 9 中,CompletableFuture API 得到了进一步增强。以下是对 API 进行的相关更改。
- 支持延迟和超时。
- 改进对子类的支持。
- 添加了新的工厂方法。
支持延迟和超时
public CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit)
如果在给定超时之前未完成,则此方法使用给定值完成此 CompletableFuture。
public CompletableFuture<T> orTimeout(long timeout, TimeUnit unit)
如果在给定超时之前未完成,则此方法使用 TimeoutException 异常完成此 CompletableFuture。
改进对子类的支持
public Executor defaultExecutor()
它返回用于未指定 Executor 的异步方法的默认 Executor。可以在子类中重写此方法以返回 Executor,以提供至少一个独立线程。
public <U> CompletableFuture<U> newIncompleteFuture()
返回 CompletionStage 方法要返回的类型的新的不完整 CompletableFuture。CompletableFuture 类的子类应重写此方法以返回与该 CompletableFuture 相同类的实例。默认实现返回 CompletableFuture 类的实例。
新的工厂方法
public static <U> CompletableFuture<U> completedFuture(U value)
此工厂方法返回一个新的 CompletableFuture,它已使用给定值完成。
public static <U> CompletionStage<U> completedStage(U value)
此工厂方法返回一个新的 CompletionStage,它已使用给定值完成,并且仅支持接口 CompletionStage 中存在的方法。
public static <U> CompletionStage<U> failedStage(Throwable ex)
此工厂方法返回一个新的 CompletionStage,它已使用给定异常异常完成,并且仅支持接口 CompletionStage 中存在的方法。
其他功能
除了提到的功能外,Java 9 还对 JDK 平台进行了大量增强。其中一些列在下面。
- GC(垃圾收集器)改进
- 堆栈遍历 API
- 过滤传入的序列化数据
- 弃用 Applet API
- 优化字符串连接
- 增强的 Method Handles
- Java 平台日志记录 API 和服务
- 紧凑字符串
- Nashorn 的解析器 API