应使用 URI 类而非 URL 类解析网络地址,因 URI 符合 RFC 3986、支持归一化、相对解析及安全字段提取,而 URL 仅用于建立连接且解析不可靠。

Java 的 URL 类不适合解析网络地址 —— 它只做基础解析,不处理相对路径、不标准化、不校验结构,且无法安全提取 host/port/path 等字段。真正要“解析”,该用 URI 类;URL 本质是定位资源的“可打开连接”,不是解析器。
为什么 URL 的 getHost() / getPort() 可能返回 null 或错误值
因为 URL 构造时不做语法验证,也不归一化输入。比如:
new URL("http://example.com:8080//path///to?k=v#frag")
它会原样保留双斜杠、多余路径分隔符,getPath() 返回 "//path///to";getPort() 对于默认端口(如 http 的 80)返回 -1,而不是 80;若协议不识别(如 foo://...),getHost() 可能直接抛 MalformedURLException 或返回空字符串。
- 协议必须是已注册的(
http、https、file、jar等),否则部分方法行为未定义 - 不支持 RFC 3986 中的 IPv6 字面量写法(如
[::1])的健壮解析 - 查询参数(
query)和片段(fragment)不会被解码,getQuery()返回原始百分号编码字符串
用 URI 替代 URL 解析地址的正确姿势
URI 是纯语法解析器,符合 RFC 3986,支持相对 URI 解析、自动归一化、安全字段提取。常见操作:
立即学习“Java免费学习笔记(深入)”;
- 构造:用
new URI("...")(注意捕获URISyntaxException) - 获取标准字段:
getScheme()、getAuthority()、getHost()、getPort()(未指定时返回-1)、getPath()(已归一化,如/path/to)、getQuery()(原始编码)、getFragment() - 解析相对路径:
baseUri.resolve(relativeUri),比URL的resolve()更可靠 - 需要转成可连接的
URL?用uri.toURL(),但仅当uri.isAbsolute() && uri.getScheme() != null时才安全
遇到带用户信息或特殊端口的 URL 怎么办
URL 的 getUserInfo() 仅对含 user:pass@host 的旧式写法有效,但现代应用基本弃用;而 URI 的 getUserInfo() 同样存在,但不应依赖它传输认证信息(HTTP Basic 应走 Header,数据库连接串另论)。
- 端口异常:如
https://example.com:443,URI.getPort()返回443,URL.getPort()也返回443;但https://example.com下,两者都返回-1—— 别硬编码默认端口,应按 scheme 判断 - IPv6 主机:
URI正确支持http://[2001:db8::1]:8080/,getHost()返回"2001:db8::1";URL在某些 JDK 版本中会解析失败 - 路径含空格或中文:
URI构造前需确保已编码(如用URLEncoder.encode(str, "UTF-8")),否则抛异常;URL构造时若未编码,可能静默截断或错乱
真正要解析地址,别碰 URL 的 getter 方法 —— 它们是为连接服务的,不是为解析设计的。用 URI,再小心处理编码、相对路径和 scheme 映射,才是稳的。










