<div dir="auto"><div>Hello <span class="gmail_chip gmail_plusreply" dir="auto"><a href="mailto:chen.l.liang@oracle.com" style="color:#15c;text-decoration:underline">@Chen Liang</a></span>,<div dir="auto"><br></div><div dir="auto">Thanks. I can agree that, after pulling up the source code, it becomes obvious what occurred. That said, I do like your suggestion of the simple String "closed" to be used as the exception message. If you are ok with that, I can start replacing once I get a JBS number.</div><div dir="auto"><br></div><div dir="auto">As for the documentation, I think the documentation is fine. Looking at the stack trace, I didn't think that the place to look was Collectors.flatMapping and how it should be used. Had I realized that from looking at that stack trace, I would have caught on quickly.</div><br><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Mon, Nov 24, 2025, 10:45 PM Chen Liang <<a href="mailto:chen.l.liang@oracle.com">chen.l.liang@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">




<div dir="ltr">
<div style="font-family:"Calibri Light","Helvetica Light",sans-serif;font-size:12pt;color:rgb(0,0,0)">
Hello, David,</div>
<div style="font-family:"Calibri Light","Helvetica Light",sans-serif;font-size:12pt;color:rgb(0,0,0)">
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)">
<br>
</div>
<div style="font-family:"Calibri Light","Helvetica Light",sans-serif;font-size:12pt;color:rgb(0,0,0)">
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)">
<br>
</div>
<div style="font-family:"Calibri Light","Helvetica Light",sans-serif;font-size:12pt;color:rgb(0,0,0)">
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)">
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)">
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)">
<br>
</div>
<div style="font-family:"Calibri Light","Helvetica Light",sans-serif;font-size:12pt;color:rgb(0,0,0)">
Regards,</div>
<div style="font-family:"Calibri Light","Helvetica Light",sans-serif;font-size:12pt;color:rgb(0,0,0)">
Chen Liang</div>
<div id="m_1909780370935795524appendonsend"></div>
<hr style="display:inline-block;width:98%">
<div id="m_1909780370935795524divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> core-libs-dev <<a href="mailto:core-libs-dev-retn@openjdk.org" target="_blank" rel="noreferrer">core-libs-dev-retn@openjdk.org</a>> on behalf of David Alayachew <<a href="mailto:davidalayachew@gmail.com" target="_blank" rel="noreferrer">davidalayachew@gmail.com</a>><br>
<b>Sent:</b> Monday, November 24, 2025 1:38 PM<br>
<b>To:</b> core-libs-dev <<a href="mailto:core-libs-dev@openjdk.org" target="_blank" rel="noreferrer">core-libs-dev@openjdk.org</a>><br>
<b>Subject:</b> Add better exception message to FileTreeIterator.hasNext()?</font>
<div> </div>
</div>
<div>
<div dir="ltr">
<div style="font-family:monospace">Hello <a id="m_1909780370935795524x_plusReplyChip-0" href="mailto:core-libs-dev@openjdk.org" target="_blank" rel="noreferrer">@core-libs-dev</a>,</div>
<div style="font-family:monospace"><br>
</div>
<div 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 style="font-family:monospace"><br>
</div>
<div style="font-family:monospace">So, I ran the following code.</div>
<div style="font-family:monospace"><br>
</div>
<div 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 style="font-family:monospace"><br>
</div>
<div 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 style="font-family:monospace"><br>
</div>
<div style="font-family:monospace">The above code threw the below stack trace.</div>
<div style="font-family:monospace"><br>
</div>
<div 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 style="font-family:monospace"><br>
</div>
<div style="font-family:monospace">Not obvious what is wrong here.</div>
<div><br>
</div>
<div>
<div 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 style="font-family:monospace"><br>
</div>
<div 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" target="_blank" rel="noreferrer">https://github.com/openjdk/jdk/blob/jdk-26%2B25/src/java.base/share/classes/java/nio/file/FileTreeIterator.java#L98</a></div>
<div style="font-family:monospace"><br>
</div>
<div 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 style="font-family:monospace"><br>
</div>
<div 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 style="font-family:monospace"><br>
</div>
<div style="font-family:monospace">Thank you for your time.</div>
<div style="font-family:monospace">David Alayachew</div>
</div>
</div>
</div>
</div>

</blockquote></div></div></div>