Java URI 类
java.net.URI
是 Java 处理统一资源标识符的核心类,用于解析、构造和操作符合 RFC 2396 标准的 URI。与 URL
类不同,URI
更侧重标识符的语法规则和组件解析,而非网络连接。下面是一份从入门到实战的完整教程。
一、URI 的核心组件
一个标准 URI 的结构示例:scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]
如:https://john:pass@example.com:8080/api/data?category=java#chapter1
组件 | 描述 | 获取方法 |
---|---|---|
Scheme | 协议(http, ftp, file) | uri.getScheme() |
Authority | 用户信息+主机+端口 | uri.getAuthority() |
Host | 域名或 IP | uri.getHost() |
Port | 端口号(未指定返回 -1) | uri.getPort() |
Path | 资源路径 | uri.getPath() |
Query | 查询参数(? 后内容) | uri.getQuery() |
Fragment | 锚点(# 后内容) | uri.getFragment() |
二、创建 URI 对象的方式
// 1. 直接通过字符串创建(推荐)
URI uri1 = new URI("https://example.com:8080/data?q=java");
// 2. 分组件构造(规避编码问题)
URI uri2 = new URI("https", "user:pass", "example.com", 443, "/search", "q=URI", "results");
// 3. 使用 URI.create()(不抛受检异常)
URI uri3 = URI.create("https://example.org");
// 4. 从 URL 转换
URL url = new URL("https://example.org/file.txt");
URI uri4 = url.toURI();
关键区别:
URI
只验证语法,URL
会尝试打开连接。优先用URI
进行标识符操作。
三、关键操作与实战代码
1. 组件解析示例
URI uri = new URI("https://user:pass@example.com:9090/docs/guide?page=2#title");
System.out.println("Scheme: " + uri.getScheme()); // https
System.out.println("User Info: " + uri.getUserInfo()); // user:pass
System.out.println("Host: " + uri.getHost()); // example.com
System.out.println("Port: " + uri.getPort()); // 9090
System.out.println("Path: " + uri.getPath()); // /docs/guide
System.out.println("Query: " + uri.getQuery()); // page=2
System.out.println("Fragment: " + uri.getFragment()); // title
2. 相对路径解析
URI base = new URI("https://example.com/api/");
URI relative = new URI("users/list");
URI resolved = base.resolve(relative);
assert Objects.equals("https://example.com/api/users/list", resolved.toString());
3. 路径标准化(移除冗余 ./
和 ../
)
URI messyUri = new URI("/a/b/.././c//d/");
URI cleanUri = messyUri.normalize();
System.out.println(cleanUri.getPath()); // 输出 /a/c/d/
4. 编码敏感字符
URI safeUri = new URI(
"http",
"google.com",
"/search space",
"q=Java&ver=1.0",
"section"
);
// 自动编码:http://google.com/search%20space?q=Java&ver=1.0#section
5. 比较 URI
URI uriA = new URI("https://example.com/a/../b");
URI uriB = new URI("https://example.com/b");
System.out.println(uriA); // https://example.com/a/../b
System.out.println(uriB); // https://example.com/b
System.out.println(uriA.equals(uriB)); // false
System.out.println(uriA.normalize().equals(uriB.normalize())); // true
System.out.println(uriA.normalize()); // https://example.com/b
System.out.println(uriB.normalize()); // https://example.com/b
6. 非法URI会报错
new URI("https://example.com/a#2#");
// 会报错,报错内容
// Exception in thread "main" java.net.URISyntaxException: Illegal character in fragment at index 23: https://example.com/a#2#
四、URI 与 URL 的互转
// URI → URL(确保 scheme 支持)
URI uri = new URI("http://example.com/file");
URL url = uri.toURL(); // 可能抛出 MalformedURLException
// URL → URI
URL url = new URL("https://example.org");
URI uri = url.toURI();
安全提示:从字符串转换 URL 时,优先使用
URI.create()
预验证,再转URL
。
五、常见问题与解决方案
问题 1:路径包含空格等特殊字符
✅ 正确方式:使用组件构造或 URLEncoder
预处理
❌ 错误:new URI("http://host/path with space")
(抛出 URISyntaxException
)
问题 2:非法的百分号编码
try {
URI uri = new URI("http://host/%xx"); // 非法的%xx
} catch (URISyntaxException e) {
System.err.println("Invalid encoding: " + e.getReason());
}
百分号本身也要做下转义。
问题 3:Windows 文件路径处理
// 使用 file 协议兼容路径
URI fileUri = new File("C:/data/file.txt").toURI();
System.out.println(fileUri); // file:/C:/data/file.txt
六、最佳实践总结
- 优先选 URI 而非 URL:标识符操作无需网络连接时用
URI
- 预验证输入:用
URI.create()
或try-catch
捕获URISyntaxException
- 组件构造防编码错误:多参数构造器自动处理编码
- 重要操作后标准化:
resolve()
和冗余路径操作后调用normalize()
- 避免路径拼接字符串:用
resolve()
代替手动拼接
通过本教程,您已掌握 URI
类的核心操作。结合具体场景灵活运用组件解析和路径操作,可高效解决 URI 处理中的各类复杂需求。