requires是java模块系统中声明模块依赖的核心语句,决定本模块能否链接并使用其他模块导出的公共api;必须写模块名(如com.github.benmanes.caffeine),不可写包名或maven坐标,java.base可省略,其余jdk模块须显式声明。

在 Java 9+ 模块系统(JPMS)中,requires 是声明模块依赖的核心语句,它决定你的模块能否在编译和运行时访问其他模块导出的公共 API。关键不是“能不能用某个类”,而是“是否被允许链接并读取那个模块”。
正确写法:只写模块名,不写包名或 Maven 坐标
模块名 ≠ 包名 ≠ Maven artifactId。例如 Caffeine 的模块名是 com.github.benmanes.caffeine,不是 com.github.benmanes.caffeine.cache(那是包名),也不是 caffeine(那是 Maven 名)。
- ✅ 正确:
requires com.github.benmanes.caffeine; - ❌ 错误:
requires com.github.benmanes.caffeine.cache;(编译报错:Module not found) - ❌ 错误:
requires caffeine;或requires com.google.guava;(无对应模块名)
哪些 requires 必须显式写,哪些可以省略
java.base 是所有模块的隐式依赖,永远不用写 requires java.base;。其余 JDK 模块(如 java.sql、java.logging、java.xml)都必须显式声明。
- 用了
Connection或PreparedStatement?→ 写requires java.sql; - 用了
Logger或LogManager?→ 写requires java.logging; - 用了
DocumentBuilder?→ 写requires java.xml; - 没用到,但 IDE 自动补全加了?→ 删掉,保持最小依赖
要不要加 transitive:看你的模块是否对外暴露了该依赖的类型
requires transitive 表示:不仅我自己要用,我还把这份“可读性”传递给依赖我的模块。它不是为了“方便”,而是为了满足 API 合约。
- 你的接口方法返回
ObjectMapper(来自 Jackson)?→requires transitive com.fasterxml.jackson.databind; - 你只是内部 new 一个
Logger记日志?→requires java.logging;(不加 transitive) - 你导出了一个泛型接口
Service<t></t>,而T是第三方库的类型?→ 需要 transitive,否则下游无法实例化
常见失败原因:光写对 requires 还不够
即使 requires 语法完全正确,以下任一条件不满足,依然会报 “module not found”:
- JAR 包里没有
module-info.class(或 MANIFEST.MF 中未声明Automatic-Module-Name) - Maven 构建时未启用模块路径(比如
maven-compiler-plugin缺少<compilerargs></compilerargs>配置--module-path) - 运行时仍用
-cp启动,而非--module-path+--module - 依赖的模块本身存在循环 require(如 A → B 且 B → A),编译器会直接拒绝
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











