Java9 新特性

接口私有方法

public interface MyInterface {
    //定义私有方法
    private void m1() {
        System.out.println("123");
    }
    
    //default中调用
    default void m2() {
        m1();
    }
}
可以在接口中声明private修饰的方法了,其实就是为了让default方法调用,当然接口外部是无法访问私有方法的

改进的try with resource

/*
    改进了try-with-resources语句,可以在try外进行初始化,在括号内填写引用名,即可实现资源自动关闭
 */
public class TryWithResource {
    public static void main(String[] args) throws FileNotFoundException {
        //jdk8以前
        try (FileInputStream fileInputStream = new FileInputStream("");
             FileOutputStream fileOutputStream = new FileOutputStream("")) {

        } catch (IOException e) {
            e.printStackTrace();
        }

        //jdk9
        FileInputStream fis = new FileInputStream("");
        FileOutputStream fos = new FileOutputStream("");
        //多资源用分号隔开
        try (fis; fos) {
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

不能使用下划线命名变量
后面的版本中会将下划线作为关键字来使用

字符串的变化
Java 9 对字符串进行了重要的内部优化和改进。主要变化有以下几点:

  1. Compact Strings (压缩字符串)

    • 在 Java 9 之前,String 类的底层实现是基于 char[],每个字符占用 2 个字节(因为 Java 中的 char 是基于 UTF-16 编码)。
    • 在 Java 9 中,字符串的内部实现改为了基于 byte[] 而不是 char[]。同时引入了一个新的字段 coder 来表示字符的编码类型(例如 LATIN1 或 UTF-16)。如果字符串只包含单字节的 Latin-1 字符集(ASCII 的扩展),则每个字符只占用 1 个字节;否则,使用 UTF-16 编码,每个字符占用 2 个字节。
    • 这样做的好处是可以减少内存占用,尤其是对于大量包含 ASCII 字符的字符串。
  2. 字符串拼接的优化

    • Java 9 通过引入 invokedynamic 指令来优化字符串拼接的性能。在之前版本中,字符串拼接通常通过 StringBuilder 实现,而在 Java 9 中,通过 invokedynamic 调用,在运行时生成更加高效的拼接代码。
    • 这使得简单的字符串拼接操作更加高效,减少了不必要的中间对象创建。
      在大多数情况下,直接使用 + 拼接字符串就已经非常高效,不再需要像以前那样担心性能问题。不过如果有非常复杂的拼接需求(例如大数据处理中的大量字符串拼接),仍然可以使用 StringBuilder 来更精确地控制内存和性能。
  3. Immutable collections with String

    • Java 9 提供了几个创建不可变集合的工厂方法,例如 List.of()Set.of()Map.of(),这些方法对于包含字符串的集合提供了更方便的操作,减少了冗余代码,提升了代码的可读性和安全性。

通过这些优化,Java 9 提升了字符串操作的内存效率和性能,特别是在处理大量字符串或频繁拼接操作时,能显著减少内存占用并提升运行时的性能。

模块化系统
Java 9 引入了一个非常重要的特性——模块化系统,也称为 Java Platform Module System (JPMS),这是自 Java 以来最大的架构变动之一。这个模块化系统通过 Project Jigsaw 实现,目的是解决 Java 应用程序随着规模增大所带来的复杂性和性能问题。

以下是 Java 9 模块化系统的关键点:

1. 模块化系统的引入

在 Java 9 之前,Java 程序是基于包(package)和 JAR 文件来组织的,随着项目规模增大,类之间的依赖和管理变得越来越复杂。Java 9 的模块化系统允许将代码组织成模块,使得系统可以更好地进行依赖管理、封装、版本控制和性能优化。

  • 模块(Module):一个模块是一个自包含的代码和资源集合,通常由多个包组成。
  • 模块描述符文件(module-info.java):每个模块通过一个 module-info.java 文件来定义,明确声明模块的依赖、暴露的 API 等信息。示例如下:
module com.example.module {
    requires java.base;
    exports com.example.api;
}
  • requires 关键字声明了当前模块的依赖项。
  • exports 关键字声明了当前模块暴露给其他模块使用的包。

2. 模块化的优点

Java 模块化带来了以下几个显著的优势:

2.1. 更好的封装性

  • 在 Java 9 之前,包中的类只要是 public 的,就可以被任何其他包访问,模块化系统通过 exports 关键字控制哪些包对外可见,哪些包是模块的内部实现,不对外暴露。这提升了代码的封装性和安全性。

2.2. 模块化JDK

  • Java 9 对整个 JDK 进行了模块化,JDK 被拆分成了更小的模块(如 java.base, java.sql, java.xml 等)。这使得你可以根据需求选择只使用某些模块,而不必加载整个 JDK。这样既提高了应用的启动速度,又减少了资源占用。

2.3. 依赖管理

  • 模块化系统明确了模块之间的依赖关系,解决了传统 Java 应用中的 类路径地狱(Classpath Hell) 问题。因为以前的类路径是一个线性结构,容易引发冲突和重复依赖,而模块化系统通过 requires 使得依赖关系更加清晰。

2.4. 编译时和运行时的可靠性

  • 模块化使得在编译时就可以检测出缺失的依赖或不正确的模块组合,避免了运行时才发现这些问题。模块化系统引入的强类型依赖关系使得运行时错误更少。

2.5. 性能优化

  • 模块化可以帮助 JVM 更好地进行性能优化,尤其是启动时间和内存占用。因为模块系统允许 JVM 只加载实际需要的模块,而不是整个 JDK,这减少了应用程序的启动开销。

3. 模块化的基本结构

  • 模块:模块是一个最小的可部署单元,通常由多个包组成,并且可能有依赖关系。
  • 模块路径(Module Path):模块化应用程序使用模块路径而不是类路径,模块路径定义了应用程序依赖的模块所在的目录或 JAR 文件。

4. 模块化对现有项目的影响

  • 对于已有的 Java 项目,模块化是向后兼容的。即使你不为项目创建 module-info.java 文件,你的代码也可以在 Java 9 中正常运行,因为所有没有模块描述符的代码会被归类为所谓的 未命名模块(unnamed module)

5. 模块化系统的挑战

  • 复杂性增加:虽然模块化带来了很多好处,但对于大型现有项目来说,迁移到模块化系统需要较多的工作,特别是处理依赖和重构模块边界。
  • 第三方库支持:一些第三方库可能还没有完全支持模块化系统,导致迁移时可能会遇到依赖问题。

6. 示例:模块化应用程序

假设我们有一个简单的模块化应用程序,分为两个模块:一个模块提供 API,另一个模块使用它。

模块1:com.example.api

// module-info.java
module com.example.api {
    exports com.example.api;
}

package com.example.api;

public class HelloService {
    public String sayHello() {
        return "Hello, Java 9!";
    }
}

模块2:com.example.app

// module-info.java
module com.example.app {
    requires com.example.api;
}

package com.example.app;

import com.example.api.HelloService;

public class MainApp {
    public static void main(String[] args) {
        HelloService helloService = new HelloService();
        System.out.println(helloService.sayHello());
    }
}

编译和运行

# 编译模块
javac -d mods/com.example.api src/com.example.api/module-info.java src/com.example.api/com/example/api/HelloService.java
javac -d mods/com.example.app --module-path mods src/com.example.app/module-info.java src/com.example.app/com/example/app/MainApp.java

# 运行模块
java --module-path mods -m com.example.app/com.example.app.MainApp

jshell
Java 9 引入了一个全新的工具 JShell,这是 Java 自带的一个交互式 REPL(Read-Eval-Print Loop) 环境。JShell 允许开发者在不需要编写完整类或方法的情况下,快速执行 Java 代码片段并查看结果。这对学习 Java、快速测试代码片段以及实验新功能非常有用。

JShell 的特点和优点

  1. 交互式编程

    • JShell 提供了交互式编程环境,开发者可以输入 Java 语句、表达式、变量声明等并立即看到结果,而不需要编写完整的类或 main 方法。

    例如:

    jshell> int x = 10;
    x ==> 10
    jshell> x + 5;
    $2 ==> 15
    
  2. 快速验证代码

    • JShell 非常适合用来验证小段代码的逻辑。你可以快速测试算法、表达式,或者调用 Java API 而不需要编译整个程序。JShell 是即时反馈的。
  3. 即时反馈与实验性开发

    • 在写代码时,尤其是调试或学习某个库的 API 时,JShell 能够让你迅速进行实验。例如:
    jshell> System.out.println("Hello, JShell!");
    Hello, JShell!
    
  4. 部分代码的执行

    • 在常规 Java 开发中,必须编写完整的类、方法等,但在 JShell 中,你可以执行单独的语句或表达式,例如:
    jshell> int a = 5;
    jshell> int b = 10;
    jshell> a + b;
    $3 ==> 15
    
  5. 历史命令与自动补全

    • JShell 支持命令历史功能,可以通过 updown 键浏览之前的命令,也可以使用 TAB 键进行代码的自动补全,这大大提高了效率。
  6. 保存与加载代码片段

    • 在 JShell 中你可以保存当前的代码片段到文件,也可以从文件加载代码片段进行执行。例如:

    • 保存代码:

      /save myCode.jsh
      
    • 加载代码:

      /open myCode.jsh
      
  7. 内置命令

    • JShell 提供了一些内置命令,以 / 开头。例如:
      • /list 列出所有定义的代码片段。
      • /vars 显示当前定义的变量。
      • /methods 显示当前定义的方法。
      • /reset 重置所有状态,清除当前会话中的定义。
      • /exit 退出 JShell。
  8. 代码补全和类型推断

    • JShell 支持基于当前上下文的代码补全功能,输入代码片段时按下 Tab 键可以获得可能的补全选项。同时,JShell 也支持基本的类型推断,在不显式声明变量类型时,JShell 会自动推断类型,例如:
    jshell> var name = "Java 9";
    name ==> "Java 9"
    

JShell 的使用场景

  1. 快速测试小代码片段

    • 你可以通过 JShell 快速测试单个表达式或 Java API,进行实验性开发。例如:
    jshell> Math.max(10, 20);
    $1 ==> 20
    
  2. 学习和教学

    • 对于初学者来说,JShell 是学习 Java 的极佳工具。它允许学生在不编写复杂程序的情况下,逐步学习 Java 的语法和库,并实时看到结果。
  3. 原型开发

    • 当你要开发新功能时,可以先通过 JShell 测试各种逻辑和算法,避免写大量的模板代码,从而快速验证想法。
  4. 调试和性能分析

    • JShell 可用来快速测试和调试某个库或框架中的某个方法,验证输入和输出的正确性。

JShell 常用命令示例

  1. 查看帮助

    /help
    
  2. 查看变量

    /vars
    
  3. 查看方法

    /methods
    
  4. 查看已加载的类和代码片段

    /list
    
  5. 重置环境

    /reset
    
  6. 退出 JShell

    /exit
    

示例:使用 JShell 进行快速测试

$ jshell
|  Welcome to JShell -- Version 9
|  For an introduction type: /help intro

jshell> int a = 5;
a ==> 5

jshell> int b = 10;
b ==> 10

jshell> a + b;
$3 ==> 15

jshell> for (int i = 0; i < 5; i++) { System.out.println(i); }
0
1
2
3
4
posted @ 2024-09-27 11:27  狗狗没有坏心眼  阅读(7)  评论(0编辑  收藏  举报