Repository navigation
Typos and small issues in "File System Basics" articles of "The Java I/O API" tutorial ( https://dev.java/learn/java-io/file-system/ ) #210
Description
Hello dev.java team!
Thanks so much for all this excellent content.
Just opening an issue to report some typos and small issues I found in the "File System Basics" articles of the "The Java I/O API" tutorial ( https://dev.java/learn/java-io/file-system/ ).
For the "Listing the Content of a Directory" article, https://dev.java/learn/java-io/file-system/listing/ (archived as is at https://web.archive.org/web/20260307205120/https://dev.java/learn/java-io/file-system/listing/ )
-
The heading "Listing a the Content of a Directory" should be "Listing the Content of a Directory".
-
In the sentence "You can learn more about stream in the Stream section." , "about stream" should be "about streams".
-
The "Writing Your Own Directory Filter" appears to have multiple possible issues (same errors appear in same tutorial content also at https://docs.oracle.com/javase/tutorial/essential/io/dirs.html , https://web.archive.org/web/20260307214613/https://docs.oracle.com/javase/tutorial/essential/io/dirs.html )
- code snippet is missing the space after "new" and before "DirectoryStream"
DirectoryStream.Filter<Path> filter =
newDirectoryStream.Filter<Path>() {
(not to be confused with the "newDirectoryStream(Path, DirectoryStream.Filter) method", this is creating an instance of an anonymous class implementing the interface https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/nio/file/DirectoryStream.Filter.html )
- and, in the same snippet, the variable "file" is mis-referenced as path and Files.isDirectory() does NOT throw IOException, so that try-catch should be removed:
DirectoryStream.Filter<Path> filter =
newDirectoryStream.Filter<Path>() { // should be `new DirectoryStream.Filter<Path>()` (missing space)
public boolean accept(Path file) throws IOException {
try {
return (Files.isDirectory(path)); // SHOULD BE `(file)` NOT `(path)`
} catch (IOException x) { // <-- remove this, Files.isDirectory does not throw exceptions (see https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/nio/file/Files.html#isDirectory(java.nio.file.Path,java.nio.file.LinkOption...) )
// Failed to determine if it's a directory.
System.err.println(x);
return false;
}
}
};
If the try-catch is NOT removed, may get something like:
Error:
| exception java.io.IOException is never thrown in body of corresponding try statement
| } catch (IOException x) {
| ^----------------------...
One way to rewrite this snippet might be:
DirectoryStream.Filter<Path> filter =
new DirectoryStream.Filter<Path>() {
public boolean accept(Path file) {
return Files.isDirectory(file);
}
};
- The sentences,
To match *, ?, or the other special characters, you can escape them by using the backslash character, .
For example: \ matches a single backslash, and ? matches the question mark."
appear to be missing the extra ""s to escape the characters, that is I believe they meant "\ matches a single backslash" for example,
and there is also an erroneous ", ." after "character" instead of "." .
In "Links, Symbolics and Otherwise", https://dev.java/learn/java-io/file-system/links/ (archived as is at https://web.archive.org/web/20260307205057/https://dev.java/learn/java-io/file-system/links/ )
-
It might be better to write "Links, Symbolic and Otherwise" instead of "Links, Symbolics and Otherwise"
-
re: https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/nio/file/Files.html#createSymbolicLink(java.nio.file.Path,java.nio.file.Path,java.nio.file.attribute.FileAttribute...)
the article says "The FileAttribute vararg enables you to specify initial file attributes that are set atomically when the link is created. However, this argument is intended for future use and is not currently implemented." I don't see in the SE 25 documentation that the FileAttribute vararg is not currently implemented, does the team have a reference to where that is stated that can be added here for clarity?
In "Accessing Resources using Paths", https://dev.java/learn/java-io/file-system/file-path/ (archived as is https://web.archive.org/web/20260307205037/https://dev.java/learn/java-io/file-system/file-path/ )
-
In the sentence "Along with the factory methods from the Files, it gives you more features than the File class, and better performances, especially to access larger files and directories."
"performances" should be "performance" -
In "lastModified() et setLastModified(): return or set the time that this file was last modified." "et" was probably intended to be "and" or a comma
-
In "The Path class, introduced in the Java SE 7 release, is one of the primary entrypoint of the java.nio.file package." , "entrypoint" should be "entrypoints"
Thanks again for all this great content! I am still reviewing this series of articles so feel free to leave open even if you address the above (I would also be happy to confirm any changes before closing if desired).
Activity
willy-b commentedon Mar 9, 2026
Adding a few more items I found while continuing through this series (thanks again!).
In the "Walking the File Tree" article, https://dev.java/learn/java-io/file-system/walking-tree/ (archived as is at https://web.archive.org/web/20260308193955/https://dev.java/learn/java-io/file-system/walking-tree/ ),
IO.println("(" + attr.size() + "bytes)");(should be+ " bytes)");),Where e.g.
(159165bytes)would presumably be intended to be(159165 bytes).In the sentence, "The Find example does precisely that. Find is similar to the UNIX find utility, but has pared down functionally." , "functionally" should be "functionality."
In the Copy example, the done() method at least has multiple issues identified so far
Files.listto count how many files were copied in a possibly recursive copyE.g. if one has folder
~/examplewith~/example/a.txt,~/example/b.txt, and~/example/subfolder/c.txt,then you will see the following obviously erroneous result using the code provided
Where one can see "a.txt", "b.txt", and "c.txt" were copied, but it says "Number of files copied: 2"; and we can confirm the "c.txt" was copied:
(2) there is an unnecessarily complicated way to get the destination path in
done()Since
destinationis of type Path, it seems unnecessary to doPaths.get(destination.toUri())and in fact it seems to work fine skipping this andreplacing
Paths.get(destination.toUri())withdestinationIn the Copy example, there is a comment "//log it and move" in an exception handler, which does not log anything
In the Copy example, if one wants particular permissions, ownership, ACL lists (if supported), or other user defined attributes (see https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/nio/file/attribute/package-summary.html ) to hold on the copy that may not be guaranteed by the author's example. Java supports multiple platforms and the
Files.copydocumentation says, even if COPY_ATTRIBUTES is passed, the handing of the attributes varies by operating system ("The exact file attributes that are copied is platform and file system dependent and therefore unspecified. ", see https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/nio/file/Files.html#copy(java.nio.file.Path,java.nio.file.Path,java.nio.file.CopyOption...) ) so in real world use that is a point I would worry about, and it might be worth noting that (someone might otherwise copy your tutorial in an inappropriate setting where attributes must be preserved during copies but are not done by Files.copy automatically on that platform). One will probably want to set any restrictive permissions/ACLs/ownership manually on each folder in the destination as it is created BEFORE copying any possibly sensitive files into it at a minimum. It seems the author went out of their way to manually copy the last modified timestamp attribute for each directory after processing it; and when setting up each folder in the destination they do copy with COPY_ATTRIBUTES (unclear why the author chose not to pass the option for the files, though on my Fedora 42 system POSIX permissions are copied even without explicitly passing COPY_ATTRIBUTES), but for anything sensitive one would probably want to double check in the code that permissions or other attributes of interest had been properly set on the folder and each file before proceeding (and ensure files/folders are not temporarily set to more permissive permissions during the process).There may be other issues in the Copy example, I am still reviewing it.
I have NOT yet reviewed the Chmod example yet, I will report back after reviewing that code carefully and testing if I find anything.
In the article "Watching a Directory for Changes", https://dev.java/learn/java-io/file-system/watching-dir-changes/ (archived as is at https://web.archive.org/web/20260308213037/https://dev.java/learn/java-io/file-system/watching-dir-changes/ ):
Thanks!
JosePaumard commentedon Mar 9, 2026
willy-b commentedon Apr 11, 2026
Thanks! Almost all issues reported above appear fixed.
Here are some more small items discovered while reading this series they may be of interest to address.
In "Watching a Directory for Changes",
https://web.archive.org/web/20260407195226/https://dev.java/learn/java-io/file-system/watching-dir-changes/ ,
under the heading "Retrieving the File Name", it currently says:
It seems that "casts the WatchEvent to a WatchEvent" should instead be "casts the WatchEvent<?> to a WatchEvent" with a wildcard instead of a generic type here.
And it seems to be an error that the code example shown is using a specific cast with a generic return type (generics are not used in the actual return, unlike in the full example later in the text):
As written in the page, the above would not compile (note this is an example PRECEDING and separate from the full WatchDir example later, which does compile),
with the following compile-time error:
Instead, the cast method probably should either be implemented to be either consistently specific like
or consistently generic in the actual example later (see below):
In the "Walking the File Tree" article, https://dev.java/learn/java-io/file-system/walking-tree/ (archived as it is at https://web.archive.org/web/20260407210613/https://dev.java/learn/java-io/file-system/walking-tree/ , archived as it was at https://web.archive.org/web/20260308193955/https://dev.java/learn/java-io/file-system/walking-tree/ ), most issues reported earlier have been resolved.
Remaining issues are,
For the Copy example ( https://web.archive.org/web/20260407210613/https://dev.java/learn/java-io/file-system/walking-tree/#copy ):
There is a comment "//log it and move" in an exception handler, which does not log anything (reported in previous comment, but it is not fixed yet)
In the visitFile method, Files.copy should probably be passed the COPY_ATTRIBUTES CopyOption as the example currently only does this for copying directories in preVisitDirectory (or consistently declare it is not copying owner/group , e.g. on Linux/MacOS setting to the current owner/group or on Windows dropping ACLs),
but I would advise a comment noting that COPY_ATTRIBUTES does NOT guarantee all permissions/ownership/ACL or other relevant information will copied per Java API spec.
Specifically, e.g.:
OpenJDK on Windows platforms unfortunately silently ignores any failure to copy security attributes or ACLs when performing Files.copy
(Source: https://github.com/openjdk/jdk/blob/988ec86dc6137d3798030a188bb9b214120a553d/src/java.base/windows/classes/sun/nio/fs/WindowsFileCopy.java#L255 ).
OpenJDK on Linux and MacOS platforms also unfortunately silently ignores any failure to copy the ownership/group part of permissions attribute information during the copying of files (e.g. if the user running the Copy program does not have permission to set the group on the original file onto the copy).
(Source: see exceptions are swallowed unless failIfUnableToCopyPosix is set, https://github.com/openjdk/jdk/blob/988ec86dc6137d3798030a188bb9b214120a553d/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java#L666 noting that even when COPY_ATTRIBUTES is set, failIfUnableToCopyBasic is set but NOT failIfUnableToCopyPosix which is always false ( https://github.com/openjdk/jdk/blob/988ec86dc6137d3798030a188bb9b214120a553d/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java#L415 )).
Nonetheless, COPY_ATTRIBUTES is needed for e.g. OpenJDK to even attempt to copy file ownership information on Unix/Linux/MacOS (not mode, which is always copied as far as I know) and on Windows for security attributes to be attempted to be copied.
I can give a simple example on Windows where another user ("otheruser") has been specifically denied access to a file,
for which the parent directory of the containing directory has inheritable access grant to the other user "otheruser".
When the dev.java Copy example is run to copy that file,
the explicit access control setting to block "otheruser" from "some_file.txt" specifically, is lost and "otheruser" automatically gains access to the copy. (Note the ACLs overall used in this example are not recommended, just used for an example.)
A preview of the result is that user
otherusercannot read the original file but can read the copy:Here is the full example:
From otheruser's perspective:
Showing "otheruser" can read "some_file.txt" in the copy but not the original.
Group "somegroup" has been quietly replaced with a different group "liveuser" during the copy. (If the Copy were run as a separate machine user, its ownership would replace the original owner and group, meaning a program using Copy without attributes under its own user would not be able to move another user's files around without possibly revoking their access, unless COPY_ATTRIBUTES were set. Though again, if the user does not have permission to set the original owner/group on the copy, it will continue without doing so in OpenJDK so should be double checked if important.)
Readers might be advised that copying the attributes might be made a program parameter, logging whether they are being copied or not so users are not surprised, and if enabled, the program could check whether POSIX is supported and if so whether attributes and owner/group of the copied file match the original file and log a message or abort/rollback if the permissions could not be preserved. A similar check could be added for Windows.
Nit: while the Find example earlier encapsulated its variables
https://web.archive.org/web/20260407210613/https://dev.java/learn/java-io/file-system/walking-tree/#find , whereas the Copy example does not
https://web.archive.org/web/20260407210613/https://dev.java/learn/java-io/file-system/walking-tree/#copy .
Also, the Replicator instance "source" variable is not guaranteed to be equal to the Files.walkFileTree "source" parameter, unlike in the Copy example given by the FileVisitor class documentation (see 2nd code sample at e.g. https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/nio/file/FileVisitor.html ). Thus, it might be better not to have the Copy/Replicator class extend FileVisitor but rather have its own nested class which implements FileVisitor and have a Replicator copy method internally invoke Files.walkFileTree passing the instance "source" variable, rather than trusting the caller to construct Replicator with the same "source" parameter as would be passed to Files.walkFileTree later by the caller.
If it is possible to re-use the Replicator to copy files again, then the "count" instance variable should probably be reset each time a copy is initiated (right now only initialized at instance initialization).
In the "Walking the File Tree" article, https://dev.java/learn/java-io/file-system/walking-tree/ (archived as it is at https://web.archive.org/web/20260407210613/https://dev.java/learn/java-io/file-system/walking-tree/ , archived as it was at https://web.archive.org/web/20260308193955/https://dev.java/learn/java-io/file-system/walking-tree/ ),
For the Chmod example ( https://web.archive.org/web/20260407210613/https://dev.java/learn/java-io/file-system/walking-tree/#chmod )
is redundant with the same check after the split
so the example could be updated to just keep the 2nd check.
The example could also check whether the file system and path supports POSIX permissions ( is
Files.getFileAttributeView(path, PosixFileAttributeView.class)null?)and give the user an informative message if the system does not support POSIX/chmod operations, instead of waiting for an UnsupportedOperationException to be thrown.
Not strictly an error, but the comma-separated multiple mode behavior does not match the Linux chmod command in that the expressions are NOT applied in sequence and removals override adds regardless of order
e.g.: the traditional "chmod" handles conflicting "=", "-" and "+" by applying them in order, "u+rwx,u-x,u-w,u+w"
Compare to the behavior of this Chmod:
An even simpler example is if one starts with revoking all permissions before granting just for the owner in the same command (e.g. "ugo=,u=rw" to clear all permissions then set read and write for the owner),
which in this Chmod example will result in all permissions being revoked with no grant to the owner:
Of course in this case the user should just use the simpler "go=,u=rw" instead and the Chmod example here will work in that case, but the actual chmod command gives a different result and does not require simplification to work.
Thanks very much!
JosePaumard commentedon Apr 13, 2026
Hello, and thank you again for your report! I just pushed a fix.
As for the examples in the Walking trees, I don't want to make them more complex than what they are. Deep diving into the complexity of file attributes, and the difference between POSIX and Windows is very interesting, but goes far beyond the scope of these examples, which is just to show how the API is working on not-too-trivial examples. Plus, they have been written about 10 years ago, and would probably need some attention.
As for your report about the check on exp / expr that is redundant, are you sure it is?
Again, thank you!
willy-b commentedon Apr 14, 2026
Re: https://dev.java/learn/java-io/file-system/walking-tree/#copy
Thanks for making the main update regarding COPY_ATTRIBUTES recommended in my last comment vs the original author's implementation leaving that off the copying of files (only on directories):
In https://web.archive.org/web/20260413125851/https://dev.java/learn/java-io/file-system/walking-tree/#copy

compared to the previous version https://web.archive.org/web/20260407210613/https://dev.java/learn/java-io/file-system/walking-tree/#copy ,
Files.copynow hasCOPY_ATTRIBUTESinvisitFile:I can confirm this fixes the simple Windows example I gave earlier (see the last comment from me):
I still recommend an additional code comment with warnings that it remains unsafe (copy will proceed even if attributes cannot be copied without warnings or errors) so people know to enforce security attributes on Windows or group/ownership on Linux/MacOS some other way:
In the Chmod example of https://dev.java/learn/java-io/file-system/walking-tree/#chmod (archived as is https://web.archive.org/web/20260413125851/https://dev.java/learn/java-io/file-system/walking-tree/#chmod )
Re:
Yes, I think you can safely remove the other author's check on
exprsbut should keep the check onexpr. Ifexprs.length() < 2,expr.length() < 2is necessarily true for allString expr: exprs.split(",")asexprare substrings ofexprs(must be same length or shorter) so the condition will be caught there. There is no operation in between the checks that is unsafe forexprs.length() < 2either, though none of the code (with or without the first check) is safe for a nullexprsso you could add a null check in the first line of the method as a separate concern.Let us review the relevant block:
The Set declarations/initializations don't affect exprs, so we can ignore them and see this as:
If exprs is not null, then exprs is a non-null String and either contains a "," or does not.
If exprs DOES NOT contain ",":
exprs.split(",")will return an array containing a single element equal to exprs, andfor (String expr: exprs.split(",")) {will execute once withexpr.equals(exprs) == true(expr and exprs will contain the same text and have the same length).expr.length() < 2will have the same value asexprs.length() < 2, and it is redundantIf exprs DOES contain ",":
exprs.split(",")will return an array containing more than one element, and each element will be a string shorter than exprs as they are substringsexprs.length() < 2was true, then definitelyexpr.length() < 2will be true asexpris a substring ofexprs, so that exception will still be thrown without the first checkexpr.length() < 2still checks something new (expr.length() < 2can be true withoutexprs.length() < 2) as each comma separated sub expression has a length requirement too, which is why I said the first check should be removed as redundant with the second (remove check on exprs length, NOT expr) though vice versa redundancy is not trueThanks: In the latest https://dev.java/learn/java-io/file-system/watching-dir-changes/
( https://web.archive.org/web/20260413132843/https://dev.java/learn/java-io/file-system/watching-dir-changes/
vs previous version https://web.archive.org/web/20260407195226/https://dev.java/learn/java-io/file-system/watching-dir-changes/ ), the following comments have been fixed:
Thanks!
Note that it still says "error" in two places there when describing a unchecked warning (not an error):
These changes are appreciated!
willy-b commentedon Apr 21, 2026
(Side note: I do not use ANY LLMs or AI in the review of dev.java or writing these issues or comments.)
JosePaumard commentedon Apr 22, 2026
Thank you again for your review! I just pushed a fix.
As for the copy example: I think I understand that the person who wrote this example (15+ years ago) did not want to trigger the call to split() in case the passed argument is not correct. Calling split() is exepensive. What can be improved are the error messages.
willy-b commentedon Apr 23, 2026
Thanks!
I can confirm in https://web.archive.org/web/20260422182728/https://dev.java/learn/java-io/file-system/walking-tree/ that the warning comment for the copy example requested is now present:
(beyond using COPY_ATTRIBUTES in Files.copy visitFile, I had requested also a warning that in sensitive cases it should be double checked with retry/rollback or other protections because
COPY_ATTRIBUTES doesn't guarantee that it will succeed and can silently fail to copy security attributes while otherwise appearing to succeed, that is as explained previously
)
I am assuming the following items I mentioned earlier in this file are ACK/WON'T FIX (fine by me just FYI):
In https://web.archive.org/web/20260422182728/https://dev.java/learn/java-io/file-system/walking-tree/ , I don't see any changes to resolve what I reported earlier on the
chmodexample, nor did I see any ACK/"WON'T FIX" comment, so repeating here:(from my earlier comment at #210 (comment) , on the dev.java Chmod example, re older snapshot https://web.archive.org/web/20260407210613/https://dev.java/learn/java-io/file-system/walking-tree/ )
Feel free to ACK the above difference between the dev.java chmod example and the Unix/Linux chmod as "WON'T FIX / INTENDED" but just wanted to confirm with you before ignoring it.
re: https://dev.java/learn/java-io/file-system/watching-dir-changes/
In the latest version (archived as is at https://web.archive.org/web/20260422182917/https://dev.java/learn/java-io/file-system/watching-dir-changes/ ),
the "Retrieving the File Name" section is now free of errors (code block that would not have compiled was fixed, incorrect types in text were fixed, mention of errors that were warnings have been fixed) but it is now missing a sentence originally present explaining why the code block is being introduced.
So what remains is to reintroduce the sentence before the code block saying
right before
Thanks!
JosePaumard commentedon Apr 23, 2026
Thank you for your review! I just piushed a fix.
As for the Copy and Chmod examples: as I told you, this is really old stuff, and I don't feel like touching them too much now. I think they need to be completely replaced by other, more focused and meaningful examples. There are too many things in these examples, and the knowledge required to understand them (as you pointed it BTW) goes way beyond the Java IO API elements they want to showcase. But that will take me too much time right now.
willy-b commentedon Apr 23, 2026
No problem at all re: the additional notes on Copy and Chmod examples.
Other than that, I don't see the fix you mention pushed ( #210 (comment) ) showing at https://dev.java/learn/java-io/file-system/watching-dir-changes/ (archived as is right now at https://web.archive.org/web/20260423221638/https://dev.java/learn/java-io/file-system/watching-dir-changes/?no_cache=true , compare to previous https://web.archive.org/web/20260422182917/https://dev.java/learn/java-io/file-system/watching-dir-changes/ ) (you could also send a pull request but I am not trying to change your team's process).
That is, as mentioned in my previous comment I think a sentence dropped during your changes still needs to be reintroduced before the code block saying
right before the (now fixed in an earlier update, see earlier in these comments) code block:
Thanks very much for your support!
JosePaumard commentedon Apr 24, 2026
Thank you for pointing this! From what I see, I think the fix is online now.
willy-b commentedon Apr 27, 2026
Thanks!
In the latest version of https://dev.java/learn/java-io/file-system (archived as is at https://web.archive.org/web/20260426204428/https://dev.java/learn/java-io/file-system/?cache=false )
Typo: In the section description sentence
"How to ... delete directory" should be "How to ... delete directories".
Typo: In the section heading
I think it should be "Managing File Attributes". See e.g. the usage in the Javadoc at https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/nio/file/attribute/package-summary.html .
In the latest version of https://dev.java/learn/java-io/file-system/file-path/ (archived as is at https://web.archive.org/web/20260426204506/https://dev.java/learn/java-io/file-system/file-path/?cache=false ),
There should probably be a warning added to "setReadable"/"setWritable"/"setExecutable" noting these only update the owner's permissions by default (there is a 2-arg form that tries to update for others as well but does not allow fine-grained user, group, all control):
E.g. on Linux, using setReadable(false) on a file appears to make it inaccessible (
cat /tmp/somefilegivescat: /tmp/somefile: Permission denied, but it can fail to remove the ability for other users to read it, even if the current user is the owner and could revoke all read permissions, so that another user can)Instead or in addition, this should probably recommend to use NIO POSIX File Permissions controls like Files.setPosixFilePermissions(java.nio.file.Path,java.util.Set) ( https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/nio/file/Files.html#setPosixFilePermissions(java.nio.file.Path,java.util.Set) ) instead (or Files.setAttribute with POSIX or other permission attributes, like ACLs on some Windows setups as in the example in the Javadoc at https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/nio/file/attribute/AclFileAttributeView.html ).
(Cross-link: This is not to be confused with the example of Files.copy dropping ACLs on Windows and group/ownership info that you made updates for in response to the earlier comment, discussed in Typos and small issues in "File System Basics" articles of "The Java I/O API" tutorial ( https://dev.java/learn/java-io/file-system/ ) #210 (comment) , but also pertains to access.)
In the later java.io.File , java.nio.file comparison table, when giving the alternative for setExecutable, setReadable, setReadOnly, setWritable:
NIO Files.setAttribute is mentioned (which is generally applicable) but not Files.setPosixFilePermissions which has the closest correspondence to those methods mentioned from java.io.File.
and in the java.io.File , java.nio.file comparison table there is also:
which might mention that java.nio.file also has Files.list which returns a Stream instead of the DirectoryStream<Path> returned by Files.newDirectoryStream.
In the latest version of https://dev.java/learn/java-io/file-system/path/ (archived as is at https://web.archive.org/web/20260426222417/https://dev.java/learn/java-io/file-system/path/?cache=false )
In the OS comparison table
should be "Method invoked"
(screenshot from older snapshot, but not fixed yet)
AND
I think the column for getName(0) is left blank by mistake under Solaris OS and should also be "home"
(screenshot from older snapshot but still present)
Potentially Bad Link:
In the sentence
the "Checking Whether Two Paths Locate the Same File" just links to the current tutorial page where there is no such named section when it should in fact link to two pages ahead instead, https://dev.java/learn/java-io/file-system/move-copy-delete/ , which has such a section (that page archived as it is today at https://web.archive.org/web/20260426231027/https://dev.java/learn/java-io/file-system/move-copy-delete/?cache=false , relevant section is a subsection of "Checking a File or Directory").
In the latest version of https://dev.java/learn/java-io/file-system/file-system/ (archived as is at https://web.archive.org/web/20260426230100/https://dev.java/learn/java-io/file-system/file-system/?cache=false )
In the latest version of https://dev.java/learn/java-io/file-system/move-copy-delete (archived as is at https://web.archive.org/web/20260426231027/https://dev.java/learn/java-io/file-system/move-copy-delete/?cache=false ),
In the sentence,
it would probably benefit readers if "Enum Types" here was a hyperlink.
In the sentence
it would probably benefit readers if "Walking the File Tree" were hyperlinked to https://dev.java/learn/java-io/file-system/walking-tree/ (archived as is at https://web.archive.org/web/20260426204140/https://dev.java/learn/java-io/file-system/walking-tree/ ).
In the sentence
"symbolics" should be "symbolic" to match the other links and the heading of that section.
In the latest version of https://dev.java/learn/java-io/file-system/metadata/ (archived as is at https://web.archive.org/web/20260427001610/https://dev.java/learn/java-io/file-system/metadata/?cache=false ),
it seems that "Managing Files Attributes" on the first line should be "Managing File Attributes" to be consistent with the very next two lines. See also e.g. the usage in the official Javadoc at https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/nio/file/attribute/package-summary.html .
In the BasicFileAttributeView explainer
I think it is potentially a little misleading to say "attributes that are required to be supported by all file system implementations" when the official documentation ( https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/nio/file/attribute/BasicFileAttributeView.html ) says "provides a view of a basic set of file attributes common to many file systems" and that these "consist of mandatory and optional file attributes" (and the descriptions of each attribute in https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/nio/file/attribute/BasicFileAttributes.html often mention "If the file system implementation does not support...").
Thanks very much again for all the excellent content! (And for providing a place to submit feedback to potentially improve it slightly for other readers by fixing small potentially distracting typos and the like.)
JosePaumard commentedon Apr 27, 2026
Thank you again for your review and report! I just pushed a fix.
9 remaining items
willy-b commentedon Jun 13, 2026
Thanks so much! I found a couple of more items while continuing to review these articles.
In the latest version of https://dev.java/learn/java-io/file-system/path/ (archived as is at https://web.archive.org/web/20260612010658/https://dev.java/learn/java-io/file-system/path/ )
The sentences
seem a bit unclear, and both sentences seem to have errors.
In the first sentence, at a minimum it seems that "if it has more elements than" should be "if it has at least as many elements as", and "these elements are equal" should be "the last N elements are equal where N is the length of the given path".
In the second sentence, "If this path has a root component" should be "If the given/other path has a root component" (to complement the first sentence, which covers the case where the OTHER/given path does not have a root component), and "both path" should be "both paths".
Compare to the documentation ( https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/nio/file/Path.html#endsWith(java.nio.file.Path) )
On the latest version of https://dev.java/learn/java-io/file-system/creating-reading-directories/ (archived as is at https://web.archive.org/web/20260612045659/https://dev.java/learn/java-io/file-system/creating-reading-directories/ )
The link
links to https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/nio/file/Files.html#createTempDirectory(java.nio.file.Path,java.lang.String,java.nio.file.attribute.FileAttribute...) when it should link to https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/nio/file/Files.html#createTempDirectory(java.lang.String,java.nio.file.attribute.FileAttribute...) .
Thanks!
JosePaumard commentedon Jun 15, 2026
Thank you again for your report! A fix is on its way.
willy-b commentedon Jun 19, 2026
Thanks, it looks like there were some regressions in the dev.java team's latest change (noting I do not get to review the changes the team will make in response to my comments before they go up, and I do not edit the pages myself) and the 2nd item reported above was not fixed yet.
In the latest version of https://dev.java/learn/java-io/file-system/path/ (archived as is at https://web.archive.org/web/20260619204037/https://dev.java/learn/java-io/file-system/path/ ) (I do not propose direct edits nor get a chance to review these before they make the changes)
It appears there were some regressions that came in when the dev.java team split what was previously a combined description of startsWith/endsWith into separate "Does a Path Start with Another Path?" and "Does a Path End with Another Path?" sections in https://web.archive.org/web/20260619204037/https://dev.java/learn/java-io/file-system/path/ vs the previous https://web.archive.org/web/20260612010658/https://dev.java/learn/java-io/file-system/path/ .
In the "Does a Path Start with Another Path?" section
"the second one takes a Path: endsWith(Path)" should be "the second one takes a Path: startsWith(Path)", as they are still talking about overloads of "startsWith" in this rewritten version at this point (comparing the one that takes a String with the one that takes a Path).
Then, in the parallel "Does a Path End with Another Path?" section below that,
"There are two overloads of the Path.startsWith() and Path.endsWith() methods. " should just be "There are also two overloads of the Path.endsWith() method",
and "the second one takes a endsWith(String)" should be "the second one takes a Path: endsWith(Path)".
This was reported in a comment above,
but it is still the case in the latest version of https://dev.java/learn/java-io/file-system/creating-reading-directories/ (archived as is at https://web.archive.org/web/20260619205516/https://dev.java/learn/java-io/file-system/creating-reading-directories/ )
that the link
links to https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/nio/file/Files.html#createTempDirectory(java.nio.file.Path,java.lang.String,java.nio.file.attribute.FileAttribute...) when it should link to https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/nio/file/Files.html#createTempDirectory(java.lang.String,java.nio.file.attribute.FileAttribute...) .
In the latest version of https://dev.java/learn/java-io/file-system/file-path/ (archived as is at https://web.archive.org/web/20260619222351/https://dev.java/learn/java-io/file-system/file-path/ )
In the sentences
for "Files.createTempFile(Path, String, FileAttributes<?>)", the fragment is "createTempFile(java.nio.file.Path,java.lang.String,java.lang.String,java.nio.file.attribute.FileAttribute...)" with 4 args (last is a vararg),
corresponding to "createTempFile(Path dir, String prefix, String suffix, FileAttribute<?>... attrs)" , but the link text only has 3 arguments. It should be corrected to match the 4 argument form in the documentation (
https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/nio/file/Files.html#createTempFile(java.nio.file.Path,java.lang.String,java.lang.String,java.nio.file.attribute.FileAttribute...) ).
Thanks very much!
JosePaumard commentedon Jun 22, 2026
Thank you again for your report! A fix is on its way.
willy-b commentedon Jun 24, 2026
Thanks for the fixes!
https://dev.java/learn/java-io/file-system/path/ was almost cleared up but there is one item that was requested above that appears accidentally not yet fixed by the dev.java (see below).
In the latest version of https://dev.java/learn/java-io/file-system/path/ (archived as is https://web.archive.org/web/20260623134044/https://dev.java/learn/java-io/file-system/path/?no_cache=true )
Previously reported but not yet fixed by the dev.java team:
In the sentence
"the second one takes a endsWith(String)" should be "the second one takes a Path: endsWith(Path)"
In the latest version of https://dev.java/learn/java-io/file-system/file-path/ (archived as is at https://web.archive.org/web/20260624172443/https://dev.java/learn/java-io/file-system/file-path/ )
the heading "Introducing the Legacy File Class" has a capital "L" in the text but a lowercase "l" in the sidebar
"legacy" should be "Legacy".
In the latest version of https://dev.java/learn/java-io/file-system/path/ (archived as is at https://web.archive.org/web/20260624141348/https://dev.java/learn/java-io/file-system/path/ ),
In the section "Using the Path.of() Factory methods", in the sentence
I think "string" was intended to be "strings", as the method being discussed is "static Path of(String first,
String... more)" documented at https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/nio/file/Path.html#of(java.lang.String,java.lang.String...) which describes the vararg as "additional strings to be joined to form the path string".
In the latest version of https://dev.java/learn/java-io/file-system/path/ (archived as is at https://web.archive.org/web/20260624141348/https://dev.java/learn/java-io/file-system/path/ ),
In the sentence
descriptions of the examples are not typically past tense in these articles so it may be better to say "The following code uses" rather than "used".
For a first example, consider that a few sentences down before a diagram it is said:
Or compare the sentence introducing the next code snippet after this one
which uses the present tense "The following code snippet defines".
Thanks!
JosePaumard commentedon Jun 25, 2026
Thank you again for your report! A fix is on its way.
willy-b commentedon Jun 28, 2026
Thanks! Here are more potential items I found during continued review of this tutorial series, which you may be interested to fix.
In the latest version of https://dev.java/learn/java-io/file-system/walking-tree/ (archived as is at https://web.archive.org/web/20260627193328/https://dev.java/learn/java-io/file-system/walking-tree/ )
In the sentences
should "If returned from the postVisitDirectory() method, no further siblings are visited" say "If returned from the visitFile() method, no further siblings are visited" instead (replace "postVisitDirectory()" with "visitFile()")?
Nothing further will happen for a given directory anyway by the time postVisitDirectory() completes so this doesn't seem to make sense to describe SKIP_SIBLINGS as stopping further activity in a directory, and the effect of SKIP_SIBLINGS when returned by visitFile() which is what is described here, is not yet mentioned, so it seems visitFile() may have been accidentally swapped by the author for postVisitDirectory() here.
See also the OpenJDK source code, at https://github.com/openjdk/jdk/blob/548a95379f159a0dc369f6bb80d8167ec835c7cd/src/java.base/share/classes/java/nio/file/Files.java#L2566 where it is confirmed that SKIP_SIBLINGS is ignored when returned by postVisitDirectory (remapped to CONTINUE):
In the code snippet, on the line
the parenthesis before "if" should be removed, so that "(if" becomes "if".
In the sentence
"visitFiles()" should be "visitFile()" (remove errant trailing "s" and also have a hyperlink added to be consistent with "preVisitDirectory()").
In the sentence
it would be consistent with most other method mentions in this article and useful to the reader to hyperlink "walkFileTree()" to one of its overloads, e.g. "walkFileTree()" ( https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/nio/file/Files.html#walkFileTree(java.nio.file.Path,java.util.Set,int,java.nio.file.FileVisitor) ).
For the code snippet
"looks for files ... and prints those files" may be misleading as the code snippet just checks whether a single hardcoded filename matches the pattern or not.
Maybe this should say "The following code snippet checks whether a particular path ends in .java or .class and prints it to standard output if it matches."
In the latest version of https://dev.java/learn/java-io/file-system/file-path/ (archived as is at https://web.archive.org/web/20260627013953/https://dev.java/learn/java-io/file-system/file-path/ )
In the sentence
"That been said" may have been intended to be "That being said",
and "understanding the File may still be important to you." may have been intended to be "understanding the File class may still be important to you."
OR "understanding File may still be important to you." (either update "File" to "File class" or remove "the").
Same for
"the File" should probably be "the File class" or "File".
In the sentences
The description of first constructor says "creates a file" whereas the second two say "create the given file", maybe they all say "creates" (they are single methods per sentence so singular subject).
In the sentences
it may be good to double check if the verbs here should be modified to remove the "s" at the end as these have multiple methods per line (plural subjects).
So "checks" should probably be "check" here and "allows" should be "allow".
Thank you for adding a mention of setPosixFilePermissions(path,permissions) next to the legacy setReadable/setWritable/setExecutable!
You may consider though to add a note there that it is a Files method (non-legacy, NIO) provided for comparison, or as a preferred alternative, to avoid confusion as the rest of the list is intended to be legacy methods.
In the "java.io.File Functionality" column entry in the API comparison table
"listFiles" should probably also be a hyperlink, to https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/io/File.html#listFiles() or https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/io/File.html#listFiles(java.io.FilenameFilter) or https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/io/File.html#listFiles(java.io.FileFilter) .
In the "java.io.File Functionality" column entry in the API comparison table (not earlier in the page where it is linked already)
"mkdirs" should probably also be a hyperlink to https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/io/File.html#mkdirs() .
In the latest version of https://dev.java/learn/java-io/file-system/path (archived as is at https://web.archive.org/web/20260627013956/https://dev.java/learn/java-io/file-system/path/ )
In the sentence
"not check at the file system" might be simplified to "not check the file system".
In the sentences
in "share the same node, home", the word "home" is not styled as the path parts are styled (and even "home") in the rest of the example.
See the image below:
In the latest version https://dev.java/learn/java-io/file-system/move-copy-delete/ (archived as is at https://web.archive.org/web/20260628012008/https://dev.java/learn/java-io/file-system/move-copy-delete/?no_cache=true )
In the sentences
one can get the impression that when copying a link to a file,
specifying the REPLACE_EXISTING CopyOption (LinkOption implements CopyOption) alone
will cause the link at the source Path to be copied instead of the linked/target file of the source link (like specifying NOFOLLOW_LINKS ) .
But this is not the case. REPLACE_EXISTING will allow the target path to be overridden even if it is a link to somewhere else (without following THAT link),
but will not prevent copying the file specified by a link at the source Path instead of the link at the source Path itself (unless NOFOLLOW_LINKS is added).
Same at
"If the target is a symbolic link, the link itself is copied" should be "If the target is a symbolic link, the link itself is replaced" ("copied" should be "replaced" in the context of "REPLACE_EXISTING").
I think there is confusion due to the fact that when the source Path is a link, one refers to the path specified by the link as the link "target"
and then this method also takes two Paths, a "source" and a "target". So there are a couple of different possible meanings of "target" that can come up in this example.
When the documentation is discussing the "target" parameter of the copy method (which is overridden when REPLACE_EXISTING is specified,
and if the "target" parameter Path itself specifies a link, that link is overridden, not its own link target) that can become confused with whether the source parameter Path, if it is a link, is resolved to the path that link specifies (the source Path link target).
In the latest version of https://dev.java/learn/java-io/file-system/listing/ (archived as is at https://web.archive.org/web/20260627184612/https://dev.java/learn/java-io/file-system/listing/ )
In the sentence
it might be more precise to replace "The class that implements the DirectoryStream interface also implements Iterable" with "The DirectoryStream interface extends Iterable" (or "Iterable is a superinterface of DirectoryStream").
In the sentences
"Iterator methods cannot throw exceptions" should be "Iterator methods cannot throw checked exceptions" (which is why DirectoryIteratorException, a subclass of RuntimeException (unchecked) must wrap IOException (a checked Exception)).
In one of the code examples further down on the same page, both a direct IOException (could be thrown by the opening of resources) and a DirectoryIteratorException are caught
but in a subsequent example only IOException is caught, which might be unintentional.
In the code snippet, the one line comment
seems to have a second "//" by accident. It could be split into 2 lines or just have the 2nd inline "//" removed.
In the latest version of https://dev.java/learn/java-io/file-system/watching-dir-changes/ (archived as is at https://web.archive.org/web/20260627225209/https://dev.java/learn/java-io/file-system/watching-dir-changes/ ),
In the sentences
The link to "pollEvents()" points to the WatchService, erroneously linking to https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/nio/file/WatchService.html#pollEvents() [wrong]
when the method belongs to the WatchKey, it should link to https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/nio/file/WatchKey.html#pollEvents() [correct].
That is "WatchService.html" should be "WatchKey.html" in the URL.
In the WatchDir example, in the main method, after
it would complete the input validation to add an
else ifaborting with a usage message when there is more than 1 argument if the first argument is not-r:otherwise someone can do e.g.
java WatchDir dir -rwithout error but without the intended behavior.Thanks so much!
JosePaumard commentedon Jun 29, 2026
Thank you for your report! A fix is on its way.
As for the last example. This is the kind of legacy example I really don't like, where managing the errors of a command line becomes more important than what the example is supposed to show. You can have dirs named -r...
willy-b commentedon Jul 4, 2026
Thanks very much!
I am re-reviewing everything and looking for any other regressions but I see the following right away in those latest changes and so want to let you know.
In the latest version of https://dev.java/learn/java-io/file-system/walking-tree/ (archived as is in https://web.archive.org/web/20260704171655/https://dev.java/learn/java-io/file-system/walking-tree/ )
Thanks for the last update by the dev.java team!
The code was updated to match the description (instead of changing the description as suggested),
which is fine, but there are two issues:
if the "root" is a path with multiple parts,
it will fail as written, so either a
.map(p -> p.getFileName())should be added after.list(root)or the glob pattern should use a double star "**" instead of "*" to match including the leading slashes/directories .What the dev.java team wrote, with comments added on what needs to change to work as described:
In the latest version of https://dev.java/learn/java-io/file-system/file-path/ (archived as is at https://web.archive.org/web/20260704171824/https://dev.java/learn/java-io/file-system/file-path/ )
In the text
it may have been intended to be "understanding the File class may still be important to you." OR "understanding File may still be important to you." (either update "File" to "File class" or remove "the") Same for
where "the File" should probably also be "the File class" or "File" .
These were reported in my last comment as well but I am repeating them as they were not yet fixed or ack'd as of https://web.archive.org/web/20260704171824/https://dev.java/learn/java-io/file-system/file-path/ .
For setPosixFilePermissions(path,permissions) next to the legacy setReadable/setWritable/setExecutable, "allow" should be "allows" here (unlike the preceding ones I asked for "allow" as they had plural subjects, but this is one method).
You may also consider though to add a note there that it is a Files method (non-legacy, NIO) provided for comparison, or as a preferred alternative, to avoid confusion as the rest of the list is intended to be legacy methods. (This was mentioned in the last comment too but has not yet been fixed or ack'd as of https://web.archive.org/web/20260704171824/https://dev.java/learn/java-io/file-system/file-path/ . )
In the latest version of https://dev.java/learn/java-io/file-system/watching-dir-changes/ (archived as is at https://web.archive.org/web/20260704172620/https://dev.java/learn/java-io/file-system/watching-dir-changes/ )
In the changes made by the dev.java team in response to the last comment,
it appears a condition which is not following best practices for conditionals was introduced:
No error will result from this particular condition (perhaps surprisingly), but it is not a safe practice generally to mix "&&" and "||" pairs in a compound condition without grouping.
As a best practice and to improve readability, I would humbly suggest that
args.length == 2 && !args[0].equals("-r")should be grouped with parentheses(args.length == 2 && !args[0].equals("-r")).The approach of not grouping when mixing &&,|| is NOT safe generally
since e.g.
(A || B) && (C || D)when ungrouped also becomesA || B && C || D,where
A=false,B=false,C=false,D=truesatisfies the ungrouped but not the grouped version in that case, and there are many such cases where one can easily get into trouble if not grouping.Thus IMHO it is harder on the readers of your code if you do not group when mixing &&,||, even if in the particular case it would be safe.
Thanks so much!
JosePaumard commentedon Jul 6, 2026
Thanks again you for your report! A fix is on its way.
Also, as for your report "As a legacy class, the File does not expose all the security attributes". I double checked, and the fix (... File class does not expose...) is indeed on the live site. I wonder if there could be a sync issue somewhere?
willy-b commentedon Jul 11, 2026
Thanks.
Here is another item I found:
In the latest version of https://dev.java/learn/java-io/file-system/move-copy-delete/ (archived as is https://web.archive.org/web/20260710065313/https://dev.java/learn/java-io/file-system/move-copy-delete/?no_cache=true )
In the sentence
the overload linked is incorrect: https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/nio/file/Files.html#copy(java.nio.file.Path,java.io.OutputStream) .
It should be linked to https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/nio/file/Files.html#copy(java.io.InputStream,java.nio.file.Path,java.nio.file.CopyOption...) .
JosePaumard commentedon Jul 11, 2026
Thank you again for your report! A fix is on its way.
Isn't it the same fix as the one in the other thread?
willy-b commentedon Jul 12, 2026
Yes, the comment #210 (comment) appeared on a different issue first briefly but it belongs here so I marked the other occurrence (of just the comment, not the whole issue) as a duplicate.
Thanks for resolving #210 (comment) in the latest version of https://dev.java/learn/java-io/file-system/move-copy-delete/ (archived as is at https://web.archive.org/web/20260712070754/https://dev.java/learn/java-io/file-system/move-copy-delete/ ) .
The items reported above were either resolved (or you acknowledged them as "Won't Fix"), so I am marking this closed.