<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<div style="font-family: "Calibri Light", "Helvetica Light", sans-serif; font-size: 12pt; color: rgb(0, 0, 0);" class="elementToProof">
Hello, David,</div>
<div style="font-family: "Calibri Light", "Helvetica Light", sans-serif; font-size: 12pt; color: rgb(0, 0, 0);" class="elementToProof">
I don't think this is necessary - the cause of the exception is already quite clear from the stack trace. I checked a few use sites of the no-arg constructor of IllegalStateException - many of them are in the same situation, that they are easy to understand
 once we see their location in code. I assume such a use of no-arg ISE constructor is widely accepted.</div>
<div style="font-family: "Calibri Light", "Helvetica Light", sans-serif; font-size: 12pt; color: rgb(0, 0, 0);" class="elementToProof">
<br>
</div>
<div style="font-family: "Calibri Light", "Helvetica Light", sans-serif; font-size: 12pt; color: rgb(0, 0, 0);" class="elementToProof">
For error messages, sometimes it is not feasible to be too detailed - I would think if we do add any, something like "closed" would be sufficient. Printing too many details in exceptions and log messages can sometimes constitute security risks.</div>
<div style="font-family: "Calibri Light", "Helvetica Light", sans-serif; font-size: 12pt; color: rgb(0, 0, 0);" class="elementToProof">
<br>
</div>
<div style="font-family: "Calibri Light", "Helvetica Light", sans-serif; font-size: 12pt; color: rgb(0, 0, 0);" class="elementToProof">
For the stream part, I believe both Files.walk and Stream.flatMap do their job - walk specifies you should close after use, and flatMap specifies the returned streams are closed once their elements are all taken. However, I do agree that there are possible
 documentation enhancements, that:</div>
<div style="font-family: "Calibri Light", "Helvetica Light", sans-serif; font-size: 12pt; color: rgb(0, 0, 0);" class="elementToProof">
1. Stream factories should specify if their elements are still usable after the streams are closed, and</div>
<div style="font-family: "Calibri Light", "Helvetica Light", sans-serif; font-size: 12pt; color: rgb(0, 0, 0);" class="elementToProof">
2. Stream should note that they should be closed after a terminal operation (which is the fault you made here)</div>
<div style="font-family: "Calibri Light", "Helvetica Light", sans-serif; font-size: 12pt; color: rgb(0, 0, 0);" class="elementToProof">
<br>
</div>
<div style="font-family: "Calibri Light", "Helvetica Light", sans-serif; font-size: 12pt; color: rgb(0, 0, 0);" class="elementToProof">
Regards,</div>
<div style="font-family: "Calibri Light", "Helvetica Light", sans-serif; font-size: 12pt; color: rgb(0, 0, 0);" class="elementToProof">
Chen Liang</div>
<div id="appendonsend"></div>
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> core-libs-dev <core-libs-dev-retn@openjdk.org> on behalf of David Alayachew <davidalayachew@gmail.com><br>
<b>Sent:</b> Monday, November 24, 2025 1:38 PM<br>
<b>To:</b> core-libs-dev <core-libs-dev@openjdk.org><br>
<b>Subject:</b> Add better exception message to FileTreeIterator.hasNext()?</font>
<div> </div>
</div>
<div>
<div dir="ltr">
<div class="x_gmail_default" style="font-family:monospace">Hello <a class="x_gmail_plusreply" id="x_plusReplyChip-0" href="mailto:core-libs-dev@openjdk.org" tabindex="-1">@core-libs-dev</a>,</div>
<div class="x_gmail_default" style="font-family:monospace"><br>
</div>
<div class="x_gmail_default" style="font-family:monospace">I was writing a simple script today -- find how many Java files are in each of my top level folders of my current directory.</div>
<div class="x_gmail_default" style="font-family:monospace"><br>
</div>
<div class="x_gmail_default" style="font-family:monospace">So, I ran the following code.</div>
<div class="x_gmail_default" style="font-family:monospace"><br>
</div>
<div class="x_gmail_default" style="font-family:monospace">Files<br>
    list(Path.of("."))<br>
    filter(Files::isDirectory)<br>
    collect<br>
    <br>
        Collectors.groupingBy(<br>
        Function.<Path>identity(),<br>
        Collectors<br>
            .flatMapping<br>
            (<br>
                (final Path root) -><br>
                {<br>
                    try (final Stream<Path> streamWalker = Files.walk(root))<br>
                    {<br>
                        return<br>
                            streamWalker<br>
                                .filter(Files::isRegularFile)<br>
                                .filter(file -> file.toString().endsWith(".java"))<br>
                                ;<br>
                    }<br>
                    catch (final Exception exception)<br>
                    {<br>
                        throw new RuntimeException(exception);<br>
                    }<br>
                },<br>
                Collectors.counting()<br>
            )<br>
        )<br>
        ;</div>
<div class="x_gmail_default" style="font-family:monospace"><br>
</div>
<div class="x_gmail_default" style="font-family:monospace">Now, there is a not-so-obvious bug -- when using a flatMapping Collector, no need for try-with-resources.</div>
<div class="x_gmail_default" style="font-family:monospace"><br>
</div>
<div class="x_gmail_default" style="font-family:monospace">The above code threw the below stack trace.</div>
<div class="x_gmail_default" style="font-family:monospace"><br>
</div>
<div class="x_gmail_default" style="font-family:monospace">|  Exception java.lang.IllegalStateException<br>
|        at FileTreeIterator.hasNext (FileTreeIterator.java:100)<br>
|        at Iterator.forEachRemaining (Iterator.java:132)<br>
|        at Spliterators$IteratorSpliterator.forEachRemaining (Spliterators.java:1939)<br>
|        at AbstractPipeline.copyInto (AbstractPipeline.java:570)<br>
|        at AbstractPipeline.wrapAndCopyInto (AbstractPipeline.java:560)<br>
|        at ForEachOps$ForEachOp.evaluateSequential (ForEachOps.java:153)<br>
|        at ForEachOps$ForEachOp$OfRef.evaluateSequential (ForEachOps.java:176)<br>
|        at AbstractPipeline.evaluate (AbstractPipeline.java:265)<br>
|        at ReferencePipeline.forEach (ReferencePipeline.java:632)<br>
|        at Collectors.lambda$flatMapping$0 (Collectors.java:483)<br>
|        at Collectors.lambda$groupingBy$0 (Collectors.java:1113)<br>
|        at ReduceOps$3ReducingSink.accept (ReduceOps.java:169)<br>
|        at ReferencePipeline$2$1.accept (ReferencePipeline.java:197)<br>
|        at Iterator.forEachRemaining (Iterator.java:133)<br>
|        at Spliterators$IteratorSpliterator.forEachRemaining (Spliterators.java:1939)<br>
|        at AbstractPipeline.copyInto (AbstractPipeline.java:570)<br>
|        at AbstractPipeline.wrapAndCopyInto (AbstractPipeline.java:560)<br>
|        at ReduceOps$ReduceOp.evaluateSequential (ReduceOps.java:921)<br>
|        at AbstractPipeline.evaluate (AbstractPipeline.java:265)<br>
|        at ReferencePipeline.collect (ReferencePipeline.java:723)<br>
|        at (#4:5)<br>
<br>
</div>
<div class="x_gmail_default" style="font-family:monospace"><br>
</div>
<div class="x_gmail_default" style="font-family:monospace">Not obvious what is wrong here.</div>
<div><br>
</div>
<div>
<div class="x_gmail_default" style="font-family:monospace">Now, the exception message is being thrown by the hasNext() method of the FileTreeIterator class. After looking at the source code of that class, it's clear what the problem is.</div>
<div class="x_gmail_default" style="font-family:monospace"><br>
</div>
<div class="x_gmail_default" style="font-family:monospace"><a href="https://github.com/openjdk/jdk/blob/jdk-26%2B25/src/java.base/share/classes/java/nio/file/FileTreeIterator.java#L98">https://github.com/openjdk/jdk/blob/jdk-26%2B25/src/java.base/share/classes/java/nio/file/FileTreeIterator.java#L98</a></div>
<div class="x_gmail_default" style="font-family:monospace"><br>
</div>
<div class="x_gmail_default" style="font-family:monospace">It throws an exception because the FileTreeWalker contained within the FileTreeIterator is closed (presumably by the try-with-resources). However, the thrown exception message is empty. This exact same
 check-then-throw logic is duplicated all over FileTreeIterator.</div>
<div class="x_gmail_default" style="font-family:monospace"><br>
</div>
<div class="x_gmail_default" style="font-family:monospace">I propose that all such instances of check-then-throw be provided with exception messages along the lines of "Cannot check for more elements because the file walker is already closed!". I am not picky
 on the wording. Just something to inform me that the issue is something is closed, as opposed to just a generic IllegalStateException. I would even accept an empty message body if the exception type communicated the issue.</div>
<div class="x_gmail_default" style="font-family:monospace"><br>
</div>
<div class="x_gmail_default" style="font-family:monospace">Thank you for your time.</div>
<div class="x_gmail_default" style="font-family:monospace">David Alayachew</div>
</div>
</div>
</div>
</body>
</html>