Java 8 中判断 /path/a 是否是 /path 的子目录的正确方法是什么?
What's the right way in Java 8 to evaluate if /path/a is a subdirectory of /path?
和标题差不多。
假设我传递了一个路径“/tmp/foo/bar”,我想特别确保该路径是路径“/tmp”的子目录,什么是最 "Java 8"ish怎么办?
具体来说,我有兴趣询问 "Given two independent paths, /foo and /foo/bar/baz how can I test if /foo/bar/baz is a subdirectory of /foo without recursing the directory tree?" 我对探索 /foo 下的所有子目录并寻找 /foo/bar/baz 下游不感兴趣。
我一直在研究
@Test
public void test() {
final Path root = Paths.get("/tmp");
final Path path0 = Paths.get("/");
final Path path1 = Paths.get("/opt/location/sub");
final Path path2 = Paths.get("/tmp/location/sub");
final Pattern ptrn = Pattern.compile("^[a-zA-Z].*$");
final Function<Path, String> f = p -> root.relativize(p).toString();
Assert.assertFalse("root",ptrn.matcher(f.apply(root)).matches());
Assert.assertFalse("path0",ptrn.matcher(f.apply(path0)).matches());
Assert.assertFalse("path1",ptrn.matcher(f.apply(path1)).matches());
Assert.assertTrue("path2",ptrn.matcher(f.apply(path2)).matches());
}
但这感觉就像我一直工作到 Java 8 的边缘,然后回到旧模式并错过了船。
boolean <a href="https://docs.oracle.com/javase/8/docs/api/java/nio/file/Path.html#startsWith-java.nio.file.Path-" rel="nofollow noreferrer">startsWith</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/nio/file/Path.html" rel="nofollow noreferrer">Path</a> other)
Tests if this path starts with the given path.
获取有意义的断言消息
与 AssertJ (JUnits 3,4,5+...)
tl;博士
import static org.assertj.core.api.Assertions.assertThat;
...
assertThat(path2 + "").startsWith("/tmp/"));
使用香草 JUnit 4
import static org.junit.Assert.assertThat; // !DEPRECATED! see: https://junit.org/junit4/javadoc/latest/org/junit/Assert.html#assertThat(T,%20org.hamcrest.Matcher)
import static org.hamcrest.core.StringStartsWith;
assertThat(path2 + "", startsWith("/tmp/"))
注意:Harmcrest 的 assertThat 已从 JUnit 5 中删除。因此,在 2020 年,更常见的做法是使用 AssertJ,这对于将来的升级更容易:https://mvnrepository.com/artifact/org.assertj/assertj-core
详细信息: Path#startsWith
的单元测试问题是它 return 是布尔值。所以失败的测试会 return 一个愚蠢的理由:
"Expected TRUE, but was FALSE"
因此,为了更好地维护单元测试/改进代码,更好的方法是使用断言框架。通过像这样开箱即用的消息传递,可以加快您的故障排除速度:
"Expecting: <"/opt/location/sub"> to start with: <"/tmp/foo">."
注意:虽然AssertJ有路径友好的方法,如isDirectory
、startsWith(::Path)
,但根据环境,它们可能导致failed to resolve actual real path
消息。因此在断言之前将 Path
转换为 String
更稳定: -- 通过 path2.toString()
-- 或者通过 path2 + ""
.
和标题差不多。
假设我传递了一个路径“/tmp/foo/bar”,我想特别确保该路径是路径“/tmp”的子目录,什么是最 "Java 8"ish怎么办?
具体来说,我有兴趣询问 "Given two independent paths, /foo and /foo/bar/baz how can I test if /foo/bar/baz is a subdirectory of /foo without recursing the directory tree?" 我对探索 /foo 下的所有子目录并寻找 /foo/bar/baz 下游不感兴趣。
我一直在研究
@Test
public void test() {
final Path root = Paths.get("/tmp");
final Path path0 = Paths.get("/");
final Path path1 = Paths.get("/opt/location/sub");
final Path path2 = Paths.get("/tmp/location/sub");
final Pattern ptrn = Pattern.compile("^[a-zA-Z].*$");
final Function<Path, String> f = p -> root.relativize(p).toString();
Assert.assertFalse("root",ptrn.matcher(f.apply(root)).matches());
Assert.assertFalse("path0",ptrn.matcher(f.apply(path0)).matches());
Assert.assertFalse("path1",ptrn.matcher(f.apply(path1)).matches());
Assert.assertTrue("path2",ptrn.matcher(f.apply(path2)).matches());
}
但这感觉就像我一直工作到 Java 8 的边缘,然后回到旧模式并错过了船。
boolean <a href="https://docs.oracle.com/javase/8/docs/api/java/nio/file/Path.html#startsWith-java.nio.file.Path-" rel="nofollow noreferrer">startsWith</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/nio/file/Path.html" rel="nofollow noreferrer">Path</a> other)
Tests if this path starts with the given path.
获取有意义的断言消息
与 AssertJ (JUnits 3,4,5+...)
tl;博士
import static org.assertj.core.api.Assertions.assertThat;
...
assertThat(path2 + "").startsWith("/tmp/"));
使用香草 JUnit 4
import static org.junit.Assert.assertThat; // !DEPRECATED! see: https://junit.org/junit4/javadoc/latest/org/junit/Assert.html#assertThat(T,%20org.hamcrest.Matcher)
import static org.hamcrest.core.StringStartsWith;
assertThat(path2 + "", startsWith("/tmp/"))
注意:Harmcrest 的 assertThat 已从 JUnit 5 中删除。因此,在 2020 年,更常见的做法是使用 AssertJ,这对于将来的升级更容易:https://mvnrepository.com/artifact/org.assertj/assertj-core
详细信息: Path#startsWith
的单元测试问题是它 return 是布尔值。所以失败的测试会 return 一个愚蠢的理由:
"Expected TRUE, but was FALSE"
因此,为了更好地维护单元测试/改进代码,更好的方法是使用断言框架。通过像这样开箱即用的消息传递,可以加快您的故障排除速度:
"Expecting: <"/opt/location/sub"> to start with: <"/tmp/foo">."
注意:虽然AssertJ有路径友好的方法,如isDirectory
、startsWith(::Path)
,但根据环境,它们可能导致failed to resolve actual real path
消息。因此在断言之前将 Path
转换为 String
更稳定: -- 通过 path2.toString()
-- 或者通过 path2 + ""
.