<!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>