<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <p>You're making this too complicated.<br>
    </p>
    <p>On their face, startsWith/endsWith(String) are misleading to both
      code authors and code readers, and that justifies their
      deprecation. It will help code authors avoid making new mistakes.
      Readers of code that uses these APIs -- even correctly -- can
      easily misinterpret the code as if it performed string-based
      testing and thus be misled about what the code is actually doing.
      In both cases, the code is better replaced with more explicit, if
      more verbose, alternatives that already exist.</p>
    <p>Certainly a file extension API would facilitate use cases that
      involve file extensions, such as inspecting a file's extension to
      determine how to process the file. I'm in favor of adding such an
      API. But that's a different topic from this one, and it should be
      handled independently.</p>
    <p>I did read all of your message but I'm not responding to most of
      it, because it doesn't establish a dependency between these two
      topics.<br>
    </p>
    <p>s'marks<br>
    </p>
    <div class="moz-cite-prefix">On 1/13/26 12:13 PM, Anthony
      Vanelverdinghe wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:AM7PPF6DBABEF0E21BF3DDA6EDCA6B5E61FE88EA@AM7PPF6DBABEF0E.EURP189.PROD.OUTLOOK.COM">
      
      <p>There are 3 questions:<br>
        <br>
        (1) should we deprecate `Path::startsWith(String)`?<br>
        (2) should we deprecate `Path::endsWith(String)`?<br>
        (3) should we add a file extension API?<br>
        <br>
        And the TL;DR: no, no, yes.<br>
        <br>
        Let's first establish why `startsWith/endsWith` add tangible
        value:<br>
        because `path.startsWith("foo")` is not equivalent to
        `path.startsWith(Path.of("foo"))`<br>
        and is much more readable than
        `path.startsWith(getFileSystem().getPath("foo"))`.<br>
        <br>
        Next, let's consider why people might want to use String-based
        `startsWith/endsWith` testing on Path instances:<br>
        <br>
        * testing file extensions = 99.9999% of the times: covered by
        `FileSystem::getPathMatcher`<br>
        * testing name elements = 0.0000999% of the times: covered by
        `Path`<br>
        * any other use cases = ~0% of the times: covered by
        `FileSystem::getPathMatcher`<br>
        <br>
        So it is always possible to do without String conversion.<br>
        In fact, it is arguably always a bad idea to do String-based
        testing,<br>
        because `path.toString().endsWith(".java")` will also match a
        file named ".java",<br>
        which on Linux-like OSes would be considered a hidden file named
        "java" that has no file extension.<br>
        So using a dedicated `PathMatcher` for testing file extensions
        is more robust and elegant.<br>
        <br>
        However, when testing file extensions we inevitably start by
        typing `path.`<br>
        (assuming we don't just use a third-party library),<br>
        first notice there's no method `getFileExtension` or such,<br>
        and then notice `endsWith(String)`<br>
        (and maybe we've also noticed `getFileName` and already have
        `path.getFileName().`).<br>
        At this point it's pure psychology:<br>
        we're looking for a method that behaves like String's
        `endsWith(String)`,<br>
        we're looking at a method with the same method signature,<br>
        and we can't imagine that the Path class does *not* have a
        method to test the filename extension,<br>
        so surely this must be it.<br>
        And obviously we ignore any hints at the contrary<br>
        (like our IDE proposing both `endsWith(Path)` and
        `endsWith(String)` for autocompletion).<br>
        And we don't bother to read the Javadoc, because in cases like
        this we can easily verify our assumptions with JShell<br>
        and equally quickly realize our assumptions are wrong.<br>
        <br>
        So yes, this is a common mistake. But this is actually an
        argument for *not* deprecating it.<br>
        Many developers have bumped into this, but as far as I can tell
        the mailing list thread in September was the first in the
        existence of the API.<br>
        And I'm unable to find any previous bug reports either.<br>
        And here's why: when we realized our assumptions were wrong, we
        read the Javadoc, realized our mistake, learned from it, and
        moved on.<br>
        The Javadoc is crystal-clear, the method overloads another
        method with the same behavior, it clearly adds value over the
        other method.<br>
        In other words: we conclude "makes sense" and don't see any
        reason to complain.<br>
        <br>
        To turn this common mistake into a rare-if-ever mistake, I see
        two (combinable) options:<br>
        <br>
        * introduce a file extension API<br>
        * replace `startsWith/endsWith` with methods
        `startsWithNames/endsWithNames`<br>
        <br>
        I don't consider deprecating `startsWith/endsWith` without
        replacement an option because:<br>
        <br>
        * these methods add value (as was also argued by Rob Spoor), so
        it's a net loss for the Java SE APIs.<br>
        And all the people that are happily using these methods today
        and are unaware of this mailing list thread will be unpleasantly
        surprised to see it deprecated<br>
        * this means breaking compilation for everyone that builds with
        "-Werror" and "no usage of deprecated APIs" is a very common
        policy.<br>
        So people will end up adding a duplicate of the deprecated
        methods in their own utility libraries<br>
        * this trades one trap for another, much more subtle trap, since
        people will blindly replace `"foo"` with `Path.of("foo")`.<br>
        (We're having this very discussion because people don't read
        Javadoc.<br>
        So surely we're not expecting people to read the deprecation
        text and follow the recommendations, are we?)<br>
        Eventually they'll notice there's a bug, add `IO.println(foo)`
        and `IO.println(Path.of("foo"))`, notice these both print "foo",<br>
        but somehow `foo.endsWith(Path.of("foo"))` results in `false`,
        eventually find the culprit ... and then notice the deprecated
        `endsWith` method did exactly<br>
        what they wanted all along<br>
        * what would the rationale for the deprecation be? How would you
        document this in the Javadoc?<br>
        Now you might still say: "People who were looking for a file
        extension API regularly ended up here. If you're one of them,
        use Path::toString instead."<br>
        But once a file extension API will be available, it'll be
        extremely hard to come up with a reasonable justification for
        the deprecation.<br>
        And as argued above, simple String-based comparisons are rarely,
        if ever, the most robust solution<br>
        * for `startsWith` in particular: the only argument to deprecate
        it seems to be "for the sake of symmetry"<br>
        <br>
        Anthony</p>
      <div class="moz-cite-prefix">On 1/12/2026 8:36 PM, Stuart Marks
        wrote:<br>
      </div>
      <blockquote type="cite" cite="mid:3316a206-c9c3-4bc0-896a-2e5a03c9b472@oracle.com">
        <p>Let's not tie these two issues together.</p>
        <p>The discussion clearly shows that the
          startsWith/endsWith(String) APIs are a trap that several
          people have fallen into. On that basis it should be
          deprecated. (Ordinarily, so as to emit a warning, and not for
          removal, so there won't be any compatibility issue.)</p>
        <p>There is also no requirement that a new API be introduced to
          replace any deprecated API. As the earlier discussion in the
          thread shows, both the path-based and the string-based use
          cases can be written using existing APIs, somewhat less
          conveniently and more verbosely; but these constructs are much
          more explicit and so are preferable to the APIs to be
          deprecated. The deprecation text should steer people toward
          the preferred constructs.<br>
        </p>
        <p>It would indeed be nice to have a file extension API, but
          this has been discussed several times and has run aground each
          time for a variety of reasons. Tying these together will hold
          up the deprecation for no good reason.</p>
        <p>Let's proceed with just the deprecation first and work on the
          file extension API separately.</p>
        <p>s'marks<br>
        </p>
        <div class="moz-cite-prefix">On 1/11/26 12:45 PM, David
          Alayachew wrote:<br>
        </div>
        <blockquote type="cite" cite="mid:CAA9v-_N24Mv5+JabZQHjuyMZVBCHE4c-_y2ByQ6omxQwyYbD3A@mail.gmail.com">
          <div dir="ltr">
            <div class="gmail_default" style="font-family:monospace">Thanks
              for the response Anthony. Messages have been arriving
              out-of-order for me, so I didn't see yours at the time of
              me writing that message.</div>
            <div class="gmail_default" style="font-family:monospace"><br>
            </div>
            <div class="gmail_default" style="font-family:monospace">I
              think introducing the file extension API first, then
              gauging the need for a deprecation before doing it is
              fine. Sounds like then that we are universally agreed on
              the first step being to add the file extension API, yes?</div>
          </div>
          <br>
          <div class="gmail_quote gmail_quote_container">
            <div dir="ltr" class="gmail_attr">On Sun, Jan 11, 2026 at
              2:06 PM Anthony Vanelverdinghe <<a href="mailto:anthonyv.be@outlook.com" moz-do-not-send="true" class="moz-txt-link-freetext">anthonyv.be@outlook.com</a>>
              wrote:<br>
            </div>
            <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
              <div>
                <p>I dissent. (Apparently my previous message wasn't
                  clear.)<br>
                  <br>
                  The right order of things is to first introduce a file
                  extension API. Then see if there's still complaints
                  about `Path::endsWith(String)`. And only then, if
                  there are, consider taking action.<br>
                  <br>
                  In my previous message I've already explained how
                  these methods add real, tangible value and actually
                  are intuitive.<br>
                  (Again, ask developers to guess how `A::foo(B)`
                  behaves, given that both `A::foo(A)` and `B::foo(B)`
                  exist, and a large majority of them will intuitively
                  guess it converts its `b` argument to an instance of
                  `A` and passes it on to `A::foo(A)`. And their
                  intuition would be correct in the case of
                  `Path::endsWith(String)`. That being said, I'll be the
                  first to admit that I've also made the mistake of
                  attempting to use `Path::endsWith(String)` to test the
                  file extension.)<br>
                  <br>
                  In hindsight, maybe `endsWithNames(String)` would've
                  been a better choice, but hindsight is 20/20.<br>
                  <br>
                  Deprecating these methods now is premature. And
                  deprecating them without replacement methods would
                  result in way more complaints than there have ever
                  been about `endsWith(String)`.<br>
                  <br>
                  Anthony</p>
                <div>On 1/11/2026 12:19 AM, David Alayachew wrote:<br>
                </div>
                <blockquote type="cite">
                  <div dir="auto">Of course.
                    <div dir="auto"><br>
                    </div>
                    <div dir="auto">I see lots of approvals and not
                      really any dissenters. Are we waiting for more
                      responses? Or is there anything we can do to kick
                      start this?</div>
                  </div>
                  <br>
                  <div class="gmail_quote">
                    <div dir="ltr" class="gmail_attr">On Fri, Jan 9,
                      2026, 10:22 PM Brian Burkhalter <<a href="mailto:brian.burkhalter@oracle.com" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">brian.burkhalter@oracle.com</a>>
                      wrote:<br>
                    </div>
                    <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
                      <div> Thanks for the corroboration.<br id="m_-8914463101179384457m_-726007501657283544lineBreakAtBeginningOfMessage">
                        <div><br>
                          <blockquote type="cite">
                            <div>On Jan 8, 2026, at 1:50 PM, David
                              Alayachew <<a href="mailto:davidalayachew@gmail.com" rel="noreferrer" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">davidalayachew@gmail.com</a>>
                              wrote:</div>
                            <br>
                            <div><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none;float:none;display:inline">Thanks
                                for reviving this.</span>
                              <div dir="auto" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none">
                                <br>
                              </div>
                              <div dir="auto" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none">
                                I am perfectly happy with the idea of
                                deprecating the
                                Path.{start,ends}With(String), and then
                                only add the file extension method.
                                Originally, I didn't know that new
                                method was on the table, so I suggested
                                a rename. But the file extension api
                                feels like the superior solution.</div>
                              <div dir="auto" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none">
                                <br>
                              </div>
                              <div dir="auto" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none">
                                10 times out of 10, if I am calling
                                endsWith, the only time I am not looking
                                for "whole" path elements is when I am
                                looking for a file extension. In every
                                other instance, the api does exactly
                                what I expect and want. And plus,
                                something like looking for a file
                                extension is better off being explicit.</div>
                            </div>
                          </blockquote>
                        </div>
                      </div>
                    </blockquote>
                  </div>
                </blockquote>
              </div>
            </blockquote>
          </div>
        </blockquote>
      </blockquote>
    </blockquote>
  </body>
</html>