Summary
Introduce a new replaceRange method to ObservableList to enable replacing a range of elements with a new list of elements in a single operation.
Problem
When wanting to replace a large range of elements, but not all elements, the current recourse is to use a combination of addAll / remove(from,to). When this is done externally to another list, listeners will receive two changes, temporarily affecting the length of the 2nd list (if the range replaced was the same length, the size of the list never really changed).
It also allows (potentially) to maintain selection state better, as items that were removed may be re-added and so can stay selected if they were selected before. This is much harder if the change is split into two separate (but not relatable) changes.
Solution
Provide an all-in-one replaceRange function, that allows an arbitrary range to be replaced with an arbitrary second range of elements. This is the most flexible option, allowing for elements to be replaced in place, to do a full or partial removal (if the new range is smaller) or replace a range and extend it at the same time (if the new range was larger).
Specification
--- a/modules/javafx.base/src/main/java/javafx/collections/ObservableList.java
+++ b/modules/javafx.base/src/main/java/javafx/collections/ObservableList.java
@@ -82,6 +83,39 @@ public interface ObservableList<E> extends List<E>, Observable {
*/
public boolean setAll(Collection<? extends E> col);
+ /**
+ * Replaces the elements in the range {@code [from, to)} with the elements
+ * from the given collection. The existing elements in the specified range
+ * are removed, and the new elements are inserted at position {@code from}.
+ * <p>
+ * If {@code from == to}, the range is empty and the elements from the given
+ * collection are inserted at position {@code from}.
+ *
+ * @param from start of the range (inclusive), must be in {@code 0..size()}
+ * @param to end of the range (exclusive), must be in {@code from..size()}
+ * @param col collection containing elements to be inserted, cannot be {@code null}
+ * @return {@code true} if this list changed as a result of the call
+ * @throws ClassCastException if the class of an element of the specified
+ * collection prevents it from being added to this list
+ * @throws NullPointerException if the specified collection contains one
+ * or more null elements and this list does not permit null
+ * elements, or if the specified collection is null
+ * @throws IllegalArgumentException if some property of an element of the
+ * specified collection prevents it from being added to this list
+ * @throws IndexOutOfBoundsException if {@code from < 0}, {@code to > size()},
+ * or {@code from > to}
+ * @since 26
+ */
+ public default boolean replaceRange(int from, int to, Collection<? extends E> col) {
+ Objects.checkFromToIndex(from, to, size());
+
+ // implicit check to ensure col != null
+ if (col.isEmpty() && from == to) {
+ return false;
+ }
+
+ remove(from, to);
+ addAll(from, col);
+
+ return true;
+ }
+
- csr of
-
JDK-8091429 ObservableList<E>#replaceRange(int from, int to, Collection<? extends E> col)
-
- Resolved
-