UPDATE: This inconsistency has been fixed in JDK 25
In Java 25+, new File("") now properly represents the current user directory.
new File("") and new File(".") yield the same canonical path, yet the former object is unusable. Consider below code, and how both objects return the same canonical path. The documentation states the canonical path is "both absolute and unique". Yet only the File created with the "." argument is actually usable.
Shouldn't an exception be thrown at some point? Either in the empty string constructor call (since the object created doesn't seem valid), or at least in getCanonicalPath (which at least declares IOException)?
import java.io.File;
import java.io.IOException;
public abstract class Test {
public static void main(String[] args) throws Exception {
testFile("");
testFile(".");
}
private static void testFile(String arg) throws IOException {
System.out.format("File constructor argument: \"%s\"\n", arg);
File g = new File(arg);
System.out.format("toString() = \"%s\"\n", g.toString());
System.out.format("getAbsolutePath() = \"%s\"\n", g.getAbsolutePath());
System.out.format("getAbsoluteFile() = \"%s\"\n", g.getAbsoluteFile());
System.out.format("getgetCanonicalPath() = \"%s\"\n", g.getCanonicalPath());
System.out.format("getgetCanonicalFile() = \"%s\"\n", g.getCanonicalFile());
System.out.format("exists() = %s\n", g.exists());
System.out.format("isDirectory() = %s\n", g.isDirectory());
System.out.println();
}
}
And the output that it produces:
File constructor argument: ""
toString() = ""
getAbsolutePath() = "C:\usr\workspace\Test"
getAbsoluteFile() = "C:\usr\workspace\Test"
getgetCanonicalPath() = "C:\usr\workspace\Test"
getgetCanonicalFile() = "C:\usr\workspace\Test"
exists() = false
isDirectory() = false
File constructor argument: "."
toString() = "."
getAbsolutePath() = "C:\usr\workspace\Test\."
getAbsoluteFile() = "C:\usr\workspace\Test\."
getgetCanonicalPath() = "C:\usr\workspace\Test"
getgetCanonicalFile() = "C:\usr\workspace\Test"
exists() = true
isDirectory() = true
While using the constructor with the empty String, you create a File instance that has two properties :
When using File("."), you create a different file :
This second file exists, not the first. The second file is consequently the only one that is supposed to respect the rule explained in getCanonicalPath :
Every pathname that denotes an existing file or directory has a unique canonical form.
As the first file is not real, the fact that their canonical paths are equal is meaningless.
Consequently, the behviour you've pointed is not a bug. It's the one we expected from the JVM.