Paths.get不能直接拼接字符串,因为它将整个字符串视为单个路径片段而非按分隔符拆解;正确做法是将各层级作为独立参数传入,由API自动适配系统分隔符。

Paths.get 为什么不能直接拼接字符串
因为 Paths.get 接收的是路径片段(String 或 Path),不是完整路径字符串。你传入 "a/b/c",它不会自动按系统分隔符拆解;在 Windows 上它会当成单个目录名,而非三层嵌套。跨平台拼接必须让 API 自己处理分隔逻辑,而不是靠手动拼 "\" 或 "/"。
正确用法:把路径拆成独立参数传给 Paths.get
每个路径层级作为单独参数传入,Paths.get 内部会根据运行时 OS 选择 File.separator 并构造正确的 Path 对象:
Path p1 = Paths.get("home", "user", "docs"); // Linux → /home/user/docs;Windows → homeuserdocs
Path p2 = Paths.get(System.getProperty("user.home"), "Downloads", "report.pdf");
- 参数可以是任意数量的
String,也可混入一个Path(如Paths.get(homeDir, "log", "app.log")) - 开头为根路径(如
"/"或"C:\")时,前面的参数会被忽略 —— 这是常见误用点,比如Paths.get("C:", "foo")实际生成C:盘相对路径,不是C:oo - 空字符串参数会被跳过,但
null会抛NullPointerException
后续拼接用 resolve(),别再用 Paths.get
已有 Path 对象后,新增片段必须用 resolve()(或 resolveSibling()),它能保持原有路径语义(相对/绝对)、处理 ".." 和 ".",且不依赖当前工作目录:
Path base = Paths.get("project");
Path full = base.resolve("src").resolve("main").resolve("java"); // project/src/main/java
Path parent = full.resolve("..").resolve("resources"); // project/src/main/resources
-
resolve()是相对拼接:如果参数是绝对路径(如"/etc/passwd"),结果就是那个绝对路径,原base被丢弃 - 需要强制“追加到末尾”且忽略参数是否绝对?用
resolveSibling()—— 它只替换最后一级,不关心参数内容 - 避免写
Paths.get(p.toString(), "sub"):这绕过了Path的语义,可能破坏..解析和符号链接处理
注意 resolve() 和 relativize() 的方向性陷阱
resolve() 是“从左往右延伸”,relativize() 是“从当前路径算到目标路径需要怎么走”。容易混淆的是:当你想从 A 到 B 的相对路径,必须用 A.relativize(B),不是 B.relativize(A):
Path a = Paths.get("/a/b/c");
Path b = Paths.get("/a/x/y");
System.out.println(a.relativize(b)); // prints: ../../x/y
- 这个结果意味着:从
a出发,先上两级,再进x/y—— 方向反了就得到错误路径 - 跨盘符(Windows)或跨挂载点(Linux)时,
relativize()可能返回空或异常,此时应改用绝对路径比较 - 所有这些操作都不访问文件系统,纯内存计算,所以快且安全
resolve() 当作字符串拼接用,或者在构造初始 Path 时混用硬编码分隔符。跨平台健壮性的核心,就是全程交由 Paths 和 Path 接口管理分隔逻辑,人只管“要哪几层”。

















