<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <p>Thank you for taking the time to clarify the trade-offs,
      especially highlighting the importance of code readers and
      readability.<br>
      <br>
      Please bear with me and allow me to express my point of view in
      terms of code authors and code readers.<br>
      <br>
      Regarding code authors, I hold that when they are misled, they
      were looking for a file extension API in virtually all cases. So I
      see a dependency here in that adding a file extension API would
      reduce the number of misleads to a negligible frequency, no larger
      than the frequency with other Java SE APIs. For example, being
      misled to write `Duration.from(aPeriod)`.<br>
      By deprecating these methods, I believe code authors will be
      misled to simply write `path.endsWith(Path.of("foo"))`, without
      considering alternative file systems (AFSs). Even code authors
      that actually know about AFSs, as it's a subtle consideration that
      is easily overlooked. And this will in turn impact code readers as
      well, as they'll wonder whether it is acceptable to ignore AFSs
      (unless the code author documented why it is). With
      `path.endsWith("foo")`, authors don't have to document anything
      and readers don't have to wonder: it just works.<br>
      <br>
      Regarding code readers, I hold that it is rare to be misled and
      that the code author is best placed to judge whether
      `path.endsWith("foo")` is misleading. For example, code readers
      would readily see that `Files.isDirectory(path) &&
      path.endsWith(".git")` looks for Git repositories. And in cases
      where the code author considers `path.endsWith("foo")` to be
      misleading, they'd simply introduce a variable to eliminate any
      confusion, e.g., `var filename = "foo"; path.endsWith(filename)`.<br>
      By deprecating these methods, code authors have one less tool for
      writing readable code. Since something like
      `path.endsWith(path.getFileSystem().getPath("foo"))` can hardly be
      considered readable, either code authors have to constrain their
      code to the default file system, or they have to introduce a new
      local variable for the argument to `endsWith`. In case of the
      former, code readers may be left to wonder whether it is
      acceptable to ignore AFSs (as explained above). In case of the
      latter, code readers might be misled to simplify `var foo =
      path.getFileSystem().getPath("foo")` to `var foo =
      Path.of("foo")`, thinking these are equivalent.<br>
      <br>
      Thanks again for reading. I don't mean to drag on the discussion,
      so if there's nothing in here that you hadn't already considered,
      we can leave it at this.<br>
      <br>
      Kind regards, Anthony</p>
    <div class="moz-cite-prefix">On 1/14/2026 7:20 PM, Stuart Marks
      wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:1867a1b2-d534-47c7-9554-3188a86bc60f@oracle.com">
      
      <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>
    </blockquote>
  </body>
</html>