<div dir="ltr"><div class="gmail_default" style="font-family:monospace">Hello <a class="gmail_plusreply" id="plusReplyChip-0" href="mailto:core-libs-dev@openjdk.org" tabindex="-1">@core-libs-dev</a>,</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="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="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">So, I ran the following code.</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="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="gmail_default" style="font-family:monospace"><br></div><div class="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="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">The above code threw the below stack trace.</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="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="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">Not obvious what is wrong here.</div><div><br></div><div><div style="font-family:monospace" class="gmail_default">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" class="gmail_default"><br></div><div style="font-family:monospace" class="gmail_default"><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 style="font-family:monospace" class="gmail_default"><br></div><div style="font-family:monospace" class="gmail_default">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" class="gmail_default"><br></div><div style="font-family:monospace" class="gmail_default">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" class="gmail_default"><br></div><div style="font-family:monospace" class="gmail_default">Thank you for your time.</div><div style="font-family:monospace" class="gmail_default">David Alayachew</div></div></div>