<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>The ListChangeBuilder implements set(int, T) as:</p>
    <div style="background-color:#ffffff;padding:0px 0px 0px 2px;">
      <div
style="color:#000000;background-color:#ffffff;font-family:"Consolas";font-size:11pt;white-space:pre;"><p
      style="margin:0;"><span style="color:#000000;">    </span><span
      style="color:#0000a0;font-weight:bold;">public</span><span
      style="color:#000000;"> </span><span
      style="color:#0000a0;font-weight:bold;">void</span><span
      style="color:#000000;"> </span><span
      style="color:#000000;background-color:#d4d4d4;">nextSet</span><span
      style="color:#000000;">(</span><span
      style="color:#0000a0;font-weight:bold;">int</span><span
      style="color:#000000;"> idx, E old) {</span></p><p
      style="margin:0;"><span style="color:#000000;">        nextRemove(idx, old);</span></p><p
      style="margin:0;"><span style="color:#000000;">        nextAdd(idx, idx + 1);</span></p><p
      style="margin:0;">
</p><p style="margin:0;"><span style="color:#000000;">    }</span></p><p
      style="margin:0;">
</p></div>
    </div>
    <p></p>
    <p>The Change interface has a `wasReplaced` method which I think
      would be applicable for this case.  SortedList however does not
      check this case (it only checks add and remove), so it may be
      possible to make an adjusment inside SortedList to be smarter
      about how to handle this.</p>
    <p>--John</p>
    <p></p>
    <div class="moz-cite-prefix">On 28/01/2026 04:50, Cormac Redmond
      wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:CAGBnJPu-hfRcr4h5_Uzb95Cix+dsMoj3mC4c7A6wdMTbtrbreg@mail.gmail.com">
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <div dir="ltr">
        <div>
          <div class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">Hi,</div>
          <div class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)"><br>
          </div>
          <div class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">I
            have noticed a troublesome quirk with SortedList which
            causes unexpected re-positioning of elements in its list.</div>
          <div class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)"><br>
          </div>
          <div class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">This
            is a noticeable problem when you are, for example, sorting a
            TableView on a column and re-insert an identical element at
            the same index in the source list (i.e., nothings changing).
            E.g., if your goal is to refresh a single row, even when
            there's no difference in the underlying object, SortedList
            can still shift its place in its arrays and hence the row
            shifts visibly in the table. On large tables, this can be a
            huge jump, outside of view. This occurs when the sort column
            value shares the same value with other rows (i.e., in my
            code sample below, multiple people are aged 62 and sorting
            is by age).</div>
          <div class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)"><br>
          </div>
          <div class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">Sample
            below code and output below. The bit in green represents
            what I would expect on each subsequent printout, but the bit
            in red shows the random re-arrangement of elements.</div>
          <div class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)"><br>
          </div>
          <div class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">There's
            no need to include a full TableView example to show this.
            But I've included a small gif too, for example.</div>
          <div class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)"><br>
          </div>
          <div class="gmail_default"
            style="font-size:small;color:rgb(0,0,0)"><font
              face="monospace"><span style="color:rgb(34,34,34)">----
                Source Initial ----</span></font></div>
          <font face="monospace">Person item [0]: Person[name=Bob,
            age=60, id=0]<br>
            Person item [1]: Person[name=Alice, age=70, id=1]<br>
            Person item [2]: Person[name=Diana, age=30, id=2]<br>
            Person item [3]: Person[name=Frank1, age=62, id=3]<br>
            Person item [4]: Person[name=Eve, age=62, id=4]<br>
            Person item [5]: Person[name=Frank2, age=62, id=5]<br>
            Person item [6]: Person[name=Jim, age=62, id=6]<br>
            Person item [7]: Person[name=Ivy, age=62, id=7]<br>
            Person item [8]: Person[name=Jack, age=53, id=8]<br>
            <br>
            ---- Sorted Initial (Subsequent Prints Should Match This,
            But Don't) ----<br>
            Person item [0]: Person[name=Diana, age=30, id=2]<br>
            Person item [1]: Person[name=Jack, age=53, id=8]<br>
            Person item [2]: Person[name=Bob, age=60, id=0]<br>
            <span style="background-color:rgb(0,255,0)"><span
                class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)"></span>Person
              item [3]: Person[name=Frank1, age=62, id=3]<br>
              Person item [4]: Person[name=Eve, age=62, id=4]<br>
              Person item [5]: Person[name=Frank2, age=62, id=5]</span><br>
            Person item [6]: Person[name=Jim, age=62, id=6]<br>
            Person item [7]: Person[name=Ivy, age=62, id=7]<br>
            Person item [8]: Person[name=Alice, age=70, id=1]<br>
            <br>
            ---- Sorted After Identical Replace Index 5 ----<br>
            Person item [0]: Person[name=Diana, age=30, id=2]<br>
            Person item [1]: Person[name=Jack, age=53, id=8]<br>
            Person item [2]: Person[name=Bob, age=60, id=0]<br>
            <span style="background-color:rgb(234,153,153)">Person item
              [3]: Person[name=Frank2, age=62, id=5]<br>
              Person item [4]: Person[name=Frank1, age=62, id=3]<br>
              Person item [5]: Person[name=Eve, age=62, id=4]</span><br>
            Person item [6]: Person[name=Jim, age=62, id=6]<br>
            Person item [7]: Person[name=Ivy, age=62, id=7]<br>
            Person item [8]: Person[name=Alice, age=70, id=1]<br>
            <br>
            ---- Sorted After Identical Replace Index 4 ----<br>
            Person item [0]: Person[name=Diana, age=30, id=2]<br>
            Person item [1]: Person[name=Jack, age=53, id=8]<br>
            Person item [2]: Person[name=Bob, age=60, id=0]<br>
            <span style="background-color:rgb(234,153,153)">Person item
              [3]: Person[name=Eve, age=62, id=4]<br>
              Person item [4]: Person[name=Frank2, age=62, id=5]<br>
              Person item [5]: Person[name=Frank1, age=62, id=3]</span><br>
            Person item [6]: Person[name=Jim, age=62, id=6]<br>
            Person item [7]: Person[name=Ivy, age=62, id=7]<br>
            Person item [8]: Person[name=Alice, age=70, id=1]<br>
            <br>
            ---- Sorted After Identical Replace Index 3 ----<br>
            Person item [0]: Person[name=Diana, age=30, id=2]<br>
            Person item [1]: Person[name=Jack, age=53, id=8]<br>
            Person item [2]: Person[name=Bob, age=60, id=0]<br>
            <span style="background-color:rgb(234,153,153)">Person item
              [3]: Person[name=Frank1, age=62, id=3]<br>
              Person item [4]: Person[name=Eve, age=62, id=4]<br>
              Person item [5]: Person[name=Frank2, age=62, id=5]</span><br>
            Person item [6]: Person[name=Jim, age=62, id=6]<br>
            Person item [7]: Person[name=Ivy, age=62, id=7]<br>
            Person item [8]: Person[name=Alice, age=70, id=1]</font><br>
          <br clear="all">
        </div>
        <div>
          <div class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">...etc.</div>
          <br>
        </div>
        <div><br>
        </div>
        <div>
          <div class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">Code:</div>
          <div class="gmail_default"
            style="font-size:small;color:rgb(0,0,0)"><font
              face="monospace">public class SortedListBehaviour {<br>
              <br>
                  public static void main(String[] args) {<br>
              <br>
                      ObservableList<Person> personList =
              FXCollections.observableArrayList();<br>
              <br>
                      personList.addAll(<br>
                          new Person("Bob", 60, 0),<br>
                          new Person("Alice", 70, 1),<br>
                          new Person("Diana", 30, 2),<br>
                          new Person("Frank1", 62, 3),<br>
                          new Person("Eve", 62, 4),<br>
                          new Person("Frank2", 62, 5),<br>
                          new Person("Jim", 62, 6),<br>
                          new Person("Ivy", 62, 7),<br>
                          new Person("Jack", 53, 8)<br>
                      );<br>
              <br>
                      SortedList<Person> sortedList = new
              SortedList<>(personList,
              Comparator.comparing(Person::age));<br>
              <br>
                      // Starting out<br>
                      printList(personList, "Source Initial");<br>
              <br>
                      // This is sorted by age, all subsequent prints
              should look like this, but they don't<br>
                      printList(sortedList, "Sorted Initial (Subsequent
              Prints Should Match This, But Don't)");<br>
              <br>
                      personList.set(5, new Person("Frank2", 62, 5)); //
              Replace with identical, at same index<br>
                      printList(sortedList, "Sorted After Identical
              Replace Index 5");<br>
              <br>
                      personList.set(4, new Person("Eve", 62, 4));  //
              Replace with identical, at same index<br>
                      printList(sortedList, "Sorted After Identical
              Replace Index 4");<br>
              <br>
                      personList.set(3, new Person("Frank1", 62, 3));
               // Replace with identical, at same index<br>
                      printList(sortedList, "Sorted After Identical
              Replace Index 3");<br>
                  }<br>
              <br>
                  private static void printList(final List<Person>
              list, final String source) {<br>
                      System.out.println("\n---- " + source + " ----");<br>
                      for (int i = 0; i < list.size(); i++) {<br>
                          final Person next = list.get(i);<br>
                          System.out.println("Person item [" + i + "]: "
              + next);<br>
                      }<br>
                  }<br>
              <br>
                  public record Person(String name, int age, int id) {<br>
                      @Override<br>
                      public boolean equals(final Object o) {<br>
                          if (o == null || getClass() != o.getClass()) {<br>
                              return false;<br>
                          }<br>
                          final Person person = (Person) o;<br>
                          return id == <a href="http://person.id"
                moz-do-not-send="true">person.id</a> && age ==
              person.age && Objects.equals(name, <a
                href="http://person.name" moz-do-not-send="true">person.name</a>);<br>
                      }<br>
              <br>
                      @Override<br>
                      public int hashCode() {<br>
                          return Objects.hash(name, age, id);<br>
                      }<br>
                  }<br>
              }</font><br>
          </div>
          <div class="gmail_default"
            style="font-size:small;color:rgb(0,0,0)"><font
              face="monospace"><br>
            </font></div>
          <div class="gmail_default"
            style="font-size:small;color:rgb(0,0,0)"><font
              face="monospace"><br>
            </font></div>
          <div class="gmail_default"
            style="font-size:small;color:rgb(0,0,0)"><font
              face="verdana, sans-serif">UI example also; the "Refresh"
              item here replaces the object with an identical object and
              the same index, yet it will often jump around the table as
              you can see, and selection can change too.</font></div>
          <div class="gmail_default"
            style="font-size:small;color:rgb(0,0,0)"><font
              face="monospace"><br>
            </font></div>
          <div class="gmail_default"
            style="font-size:small;color:rgb(0,0,0)"><img
              src="cid:part1.600MZtLx.Bd0RVsDr@gmail.com" alt="sl.gif"
              class="" width="562" height="422"><br>
          </div>
          <br>
        </div>
        <div>
          <div class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">I
            understand that strictly speaking the list is still sorted
            correctly (by age), but SortedList could make some effort to
            reduce re-arranging already-present elements.</div>
          <br>
        </div>
        <div><br>
        </div>
        <div>
          <div dir="ltr" class="gmail_signature"
            data-smartmail="gmail_signature">
            <div dir="ltr">
              <div><font face="verdana, sans-serif" color="#000000"><br>
                </font></div>
              <div><font face="verdana, sans-serif" color="#000000">Regards,</font></div>
              <div><font face="verdana, sans-serif" color="#000000"><b><br>
                  </b></font></div>
              <font face="verdana, sans-serif" color="#000000"><b>Cormac
                  Redmond</b></font>
              <div><br>
              </div>
              <div><br>
              </div>
              <div><br>
              </div>
            </div>
          </div>
        </div>
      </div>
    </blockquote>
  </body>
</html>