Skip to content

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域名或 IPuri.getHost()
Port端口号(未指定返回 -1)uri.getPort()
Path资源路径uri.getPath()
Query查询参数(? 后内容)uri.getQuery()
Fragment锚点(# 后内容)uri.getFragment()

二、创建 URI 对象的方式

java
// 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. 组件解析示例

java
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. 相对路径解析

java
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. 路径标准化(移除冗余 ./../

java
URI messyUri = new URI("/a/b/.././c//d/");
URI cleanUri = messyUri.normalize();
System.out.println(cleanUri.getPath());  // 输出 /a/c/d/

4. 编码敏感字符

java
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

java
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会报错

java
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 的互转

java
// 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:非法的百分号编码

java
try {
    URI uri = new URI("http://host/%xx"); // 非法的%xx
} catch (URISyntaxException e) {
    System.err.println("Invalid encoding: " + e.getReason());
}

百分号本身也要做下转义。

问题 3:Windows 文件路径处理

java
// 使用 file 协议兼容路径
URI fileUri = new File("C:/data/file.txt").toURI();
System.out.println(fileUri); // file:/C:/data/file.txt

六、最佳实践总结

  1. 优先选 URI 而非 URL:标识符操作无需网络连接时用 URI
  2. 预验证输入:用 URI.create()try-catch 捕获 URISyntaxException
  3. 组件构造防编码错误:多参数构造器自动处理编码
  4. 重要操作后标准化resolve() 和冗余路径操作后调用 normalize()
  5. 避免路径拼接字符串:用 resolve() 代替手动拼接

通过本教程,您已掌握 URI 类的核心操作。结合具体场景灵活运用组件解析和路径操作,可高效解决 URI 处理中的各类复杂需求。