继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

JDK9新特性学习入门:简单教程详解

喵喵时光机
关注TA
已关注
手记 241
粉丝 9
获赞 108
概述

JDK9带来了许多新的特性和改进,这篇文章将详细介绍如何学习和入门JDK9的新特性,包括JDK9的安装和配置,模块系统(Project Jigsaw)的使用方法,新增的API与工具介绍,核心语言功能的改进,内存管理与性能优化,以及实践案例分析。JDK9新特性学习入门将帮助开发者更好地理解和使用这些新功能。

JDK9新特性学习入门:简单教程详解
JDK9简介与安装

JDK9的最新版本与下载

JDK9是Java平台标准版(Java SE)的第九个主要版本,于2017年9月21日发布。JDK9引入了许多新的特性和改进,为其后续版本奠定了坚实的基础。为了确保开发体验的最新性和稳定性,建议开发者始终使用最新版本的JDK9。JDK9的最新版本可以在Oracle官方网站上找到并下载。下载页面提供了针对不同操作系统的版本,包括Windows、Linux和macOS。

安装JDK9的步骤与注意事项

  1. 下载JDK9:
    访问Oracle官方网站下载页面,选择适用于你操作系统的JDK9版本并下载。确保下载的是适用于开发者的JDK版本。

  2. 安装JDK9:
    下载完成后,根据下载的安装程序类型(.exe或.tar.gz),双击安装程序进行安装。对于Linux和macOS用户,可能需要通过终端执行安装命令。以下是一些示例命令:

    • Windows:

      1. 双击下载的安装程序(通常是一个.exe文件)。
      2. 按照安装向导的提示完成安装。
    • macOS:

      1. 打开终端。
      2. 使用Homebrew安装:
        brew tap adoptopenjdk/openjdk
        brew install --cask adoptopenjdk
    • Linux:
      1. 打开终端。
      2. 使用以下命令解压并安装:
        tar -xvf jdk-9.0.4_linux-x64_bin.tar.gz -C /usr/local
        sudo mkdir -p /usr/lib/jvm
        sudo ln -s /usr/local/jdk-9.0.4 /usr/lib/jvm/jdk-9.0.4
  3. 环境变量配置:
    为了确保JDK9能够正确地被系统识别和使用,需要设置环境变量。这包括JAVA_HOME和PATH变量。

    • Windows:
      在系统环境变量中添加JAVA_HOME指向JDK安装路径,并将%JAVA_HOME%\bin添加到系统PATH变量中。

    • macOS/Linux:
      在终端中使用以下命令设置环境变量:
      export JAVA_HOME=/usr/lib/jvm/jdk-9.0.4
      export PATH=$JAVA_HOME/bin:$PATH
  4. 验证安装:
    安装完成后,可以通过运行以下命令来验证JDK9是否正确安装:
    java -version

    这将显示你安装的Java版本,应显示为JDK9的某个版本。

注意事项

  • 兼容性:
    使用JDK9时,需要注意它可能不完全兼容旧版本的Java程序。确保你的应用程序兼容JDK9的API。
  • 默认配置:
    JDK9引入了新的默认配置,如JavaFX的移除。确保你的应用程序不需要这些默认配置。
  • 升级路径:
    如果你从较旧的JDK版本(如JDK8)升级到JDK9,建议逐步进行,确保应用程序能正常运行。
模块系统(Project Jigsaw)入门

模块系统的概念与优势

模块系统是Java 9中最显著的新特性之一,它是Project Jigsaw的一部分。模块系统通过模块定义来组织和管理Java应用程序中的类和包,这些模块定义了模块的结构、依赖关系以及如何暴露和使用模块中的资源。

模块化能够带来以下优势:

  • 清晰的依赖关系管理:
    模块声明了其依赖的其他模块,这有助于避免类路径混乱和避免不必要的类加载。
  • 安全性:
    模块化使应用程序的运行时安全性更加强大,可以限制模块间的访问权限。
  • 性能优化:
    通过模块系统,JVM在运行时能够更精确地加载和卸载类,从而提高性能。

如何在项目中使用模块系统

要使用模块系统,你需要将Java项目组织成模块,并为每个模块编写一个module-info.java文件。以下是实现模块化的步骤:

  1. 模块定义文件:
    在项目根目录下创建一个名为module-info.java的文件,定义模块名称、依赖关系、导出包以及使用的服务。

  2. 示例模块定义文件:

    module com.example.myapp {
       requires java.base;
       requires java.logging;
       exports com.example.myapp.util;
    }
    • module com.example.myapp: 模块名称为com.example.myapp
    • requires java.base: 模块依赖于java.base模块。
    • requires java.logging: 模块依赖于java.logging模块。
    • exports com.example.myapp.util: 模块导出com.example.myapp.util包,使其他模块可以访问该包中的类和接口。
  3. 构建模块化项目:
    使用javac编译器编译模块化的项目,并使用module-path--module选项指定模块路径和主模块。

    javac --module-path /path/to/modules --add-modules com.example.myapp --module-source-path src -d build
  4. 运行模块化项目:
    使用java命令运行模块化的项目,并指定主模块:

    java --module-path build --module com.example.myapp/com.example.myapp.Main
    • --module-path build:指定模块路径。
    • --module com.example.myapp/com.example.myapp.Main:指定主模块以及主模块中的主类。

通过以上步骤,可以将Java项目组织成模块化结构,利用模块系统带来的优势。

新增API与工具

Collection接口的新特性

JDK9为Collection接口引入了新的默认方法,这些方法简化了集合的使用和操作。以下是几个新增的Collection接口方法及其功能:

  • isEmpty()
    确定集合是否为空。返回true如果集合包含零个元素,否则返回false

  • removeIf(Predicate<? super E> filter)
    根据提供的谓词参数filter删除元素。该方法遍历集合中的元素,如果谓词返回true,则删除该元素。该方法返回从集合中删除的元素数。

  • replaceAll(UnaryOperator<E> operator)
    用新的元素替换集合中的每个元素。新的元素是通过提供的operator计算得出的。该方法返回集合中的元素数。

以下是一个简单示例,演示如何使用这些新方法:

import java.util.ArrayList;
import java.util.List;

public class CollectionExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Banana");
        list.add("Cherry");

        System.out.println("Original List: " + list);

        // 使用 removeIf 方法删除集合中的元素
        list.removeIf(s -> s.contains("a"));
        System.out.println("List after removeIf: " + list);

        // 使用 replaceAll 方法替换元素
        list.replaceAll(s -> s.toUpperCase());
        System.out.println("List after replaceAll: " + list);
    }
}

该示例中,首先创建了一个包含三个元素的ArrayList。然后使用removeIf方法删除包含字符'a'的元素,接着使用replaceAll方法将所有元素转换为大写。

Stream API的增强功能

JDK9进一步增强了Stream API,使得流的处理变得更加灵活和强大。以下是几个重要的新特性:

  • Stream.ofNullable(T t)
    创建一个流,包含给定的非空值,或不包含任何元素(如果值为null)。这是Stream.of的扩展版本,处理null值时更为方便。

  • Stream.concat(Stream<T> s1, Stream<T> s2)
    将两个流连接到一个新的流中。这对于合并不同来源的流特别有用。

  • Stream<T> iterate(T seed, LongFunction<T> f)
    创建一个无限流,从给定的种子值开始,使用给定的函数递归地生成每个后续元素。这是Stream.iterate方法的新版本,允许使用LongFunction作为递归函数。

  • Stream<T> iterate(T seed, UnaryOperator<T> f)
    创建一个无限流,从给定的种子值开始,使用给定的函数递归地生成每个后续元素。这是Stream.iterate方法的一个方便版本,允许使用UnaryOperator作为递归函数。

以下是一个示例,演示如何使用这些增强功能:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamExample {
    public static void main(String[] args) {
        List<String> list1 = Arrays.asList("Hello", "World");
        List<String> list2 = Arrays.asList("Foo", "Bar");

        // 使用 Stream.concat 合并两个流
        Stream<String> stream1 = Stream.concat(Stream.of("A", "B"), Stream.of("C", "D"));
        stream1.forEach(System.out::println);

        // 使用 Stream.ofNullable 创建流
        Stream<String> stream2 = Stream.ofNullable(null);
        stream2.forEach(System.out::println);

        // 使用 Stream.iterate 创建无限流
        Stream<Long> infiniteStream = Stream.iterate(1L, n -> n + 1);
        infiniteStream.limit(5).forEach(System.out::println);
    }
}

该示例中,首先使用Stream.concat合并了两个字符串流,然后使用Stream.ofNullable创建了一个流,其中包含一个null值。接着使用Stream.iterate创建了一个无限流,并限定了打印前5个元素。

这些增强功能使得流处理更加灵活、强大,为开发者提供了更多的选择和便利。

核心语言功能改进

局部变量类型推断

JDK9引入了局部变量类型推断(Local Variable Type Inference),通过使用关键字var来声明局部变量,编译器可以自动推断出变量的类型。这使得代码变得更加简洁和易读。

以下是一个示例,说明如何使用var关键字:

public class VarExample {
    public static void main(String[] args) {
        // 使用 var 关键字声明局部变量
        var list = new ArrayList<String>();
        list.add("Element 1");
        list.add("Element 2");

        // 输出 list 的类型和元素
        System.out.println(list.getClass().getName() + ": " + list);
    }
}

在这个示例中,我们使用var关键字声明了一个ArrayList<String>类型的局部变量list。编译器能够推断出list的类型为ArrayList<String>

新的弃用注解与API

JDK9引入了一些新的弃用注解和API,以更好地管理和标记不再推荐使用的代码。这些新特性有助于开发者更好地理解代码的兼容性和生命周期。

  • @Deprecated(since="JDK9", forRemoval=true)
    标记方法或类为已弃用,并指定在哪个版本中弃用。forRemoval属性表示在未来的版本中将移除该方法或类。

  • @DeprecatedAPI
    标记API为已弃用。这通常用于标记较大的API模块或包,以表明在未来版本中将移除这些API。

以下是一个示例代码,演示如何使用新的弃用注解:

import java.lang.annotation.*;

@Retention(RetentionPolicy.SOURCE)
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface DeprecatedAPI {
    String value();
}

public class DeprecatedExample {
    @Deprecated(since="JDK9", forRemoval=true)
    public void oldMethod() {
        System.out.println("This method is deprecated and will be removed in future versions.");
    }

    @DeprecatedAPI("JDK9")
    public void oldInterfaceMethod() {
        System.out.println("This method is part of a deprecated API.");
    }

    public static void main(String[] args) {
        DeprecatedExample example = new DeprecatedExample();
        example.oldMethod();
        example.oldInterfaceMethod();
    }
}

在这个示例中,我们定义了一个新的注解@DeprecatedAPI,并使用它标记了一个方法。同时,我们还使用标准的@Deprecated注解标记了一个方法,并指定了弃用版本和未来移除的计划。

这些新的弃用注解和API有助于开发者更好地理解和管理代码的生命周期,确保代码库的整洁和兼容性。

内存管理与性能优化

G1垃圾收集器的改进

JDK9对G1垃圾收集器进行了重要的改进和优化,使其在处理大内存和高并发场景时更加高效。以下是G1垃圾收集器的一些重要改进:

  • 减少Full GC停顿时间:
    通过对Young GC和Full GC的优化,G1垃圾收集器减少了长期停顿时间,提高了应用程序的响应速度。
  • 减少碎片:
    G1垃圾收集器通过减少内存碎片,提高了垃圾回收的效率,使得内存使用更加高效。
  • 改进了元数据空间管理:
    G1垃圾收集器对元数据空间的管理进行了优化,进一步减少了Full GC的停顿时间。

新增的JVM工具与指标

JDK9引入了一些新的JVM工具和指标,帮助开发者更好地监控和优化应用程序的性能:

  • jcmd工具:
    jcmd工具允许开发者发送命令到正在运行的Java应用程序,获取丰富的诊断信息和性能指标。
  • JFR(Java Flight Recorder):
    Java Flight Recorder是一种高级的性能分析工具,可以记录应用程序的运行时信息,并生成详细的报告。
  • JVM工具接口
    提供了一套标准的接口,使第三方工具可以访问JVM内部信息,如线程状态、内存使用情况等。

以下是一个简单的示例,演示如何使用jcmd工具获取Java应用程序的诊断信息:

jcmd <pid> GC.class_stats

该命令获取给定进程ID(PID)的Java应用程序的类统计信息。<pid>是Java应用程序的进程ID。

这些工具和指标使得开发者能够更深入地了解应用程序的运行情况,及早发现和解决问题。

实践与案例分析

使用JDK9新特性的简单项目开发

为了更好地理解JDK9的新特性,我们将开发一个简单的项目,其中使用了模块系统、新的API功能和性能优化技术。这个项目将实现一个简单的日志记录器,包含模块化结构、类型推断和性能监控功能。

项目结构

src/
├── module-info.java
├── com/
│   └── example/
│       └── log/
│           ├── Log.java
│           └── LogImpl.java
└── Main.java

module-info.java

module com.example.log {
    requires java.base;
    requires java.logging;
    exports com.example.log;
}

Log.java

package com.example.log;

public interface Log {
    void log(String message);
}

LogImpl.java

package com.example.log;

import java.util.logging.Logger;

public class LogImpl implements Log {
    private static final Logger logger = Logger.getLogger(LogImpl.class.getName());

    @Override
    public void log(String message) {
        logger.info(message);
    }
}

Main.java

package com.example.log;

public class Main {
    public static void main(String[] args) {
        Log log = new LogImpl();
        log.log("Hello, JDK9!");
    }
}

在这个项目中,我们定义了一个模块com.example.log,其中包含一个日志接口Log和其实现LogImplLogImpl使用Java内置的java.util.logging库实现日志记录功能。

编译和运行项目

使用以下命令编译和运行项目:

javac --module-path src -d build src/module-info.java src/com/example/log/Log.java src/com/example/log/LogImpl.java src/Main.java
java --module-path build --module com.example.log/com.example.log.Main

这将输出:

INFO: Hello, JDK9!

性能监控

为了监控性能,我们可以使用jcmd工具来收集关于应用程序的信息。例如,使用以下命令来收集GC统计信息:

jcmd <pid> GC.stats

这些信息可以帮助我们了解应用程序的内存使用和垃圾回收情况。

常见问题与解决方案汇总

在使用JDK9新特性时,可能会遇到一些常见的问题,以下是一些常见问题及其解决方案:

问题1:模块化项目的构建失败

问题描述:
在尝试构建模块化项目时,可能会遇到依赖关系或导出包的错误。

解决方案:
确保所有依赖模块都在module-info.java文件中正确声明,并检查导出包的拼写和格式是否正确。可以使用javac--module-path选项来指定模块路径。

问题2:本地变量类型推断导致编译错误

问题描述:
使用var关键字声明局部变量时,可能会遇到编译错误,提示类型无法推断。

解决方案:
确保var关键字后面紧跟初始化的变量,例如var list = new ArrayList<String>();。也可以提供更多的上下文信息帮助编译器推断类型。

问题3:jcmd工具使用时的权限问题

问题描述:
在运行jcmd工具时,可能会遇到权限不足的问题。

解决方案:
确保你有足够的权限运行jcmd工具。可以使用sudo命令来提升权限,例如:

sudo jcmd <pid> GC.stats
打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP