Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8367439

Bulk change notifications for ObservableSet and ObservableMap

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Unresolved
    • Icon: P4 P4
    • tbd
    • None
    • javafx
    • None

      While a ListChangeListener can receive notifications for bulk operations (addAll, removeAll, clear, etc.), SetChangeListener and MapChangeListener only receive notifications for individual add/replace/delete operations. For example, when mappings are added to an ObservableMap with putAll(), listeners will be invoked once for each individual mapping.

      Since there is no way for a SetChangeListener/MapChangeListener to know that more changes are coming, reacting to changes becomes difficult and potentially inefficient if an expensive operation (like reconfiguring the UI) is done for each individual change instead of once for a bulk change operation.

      We can improve the situation by adding a new method to SetChangeListener.Change and MapChangeListener.Change:

          /**
           * Gets the next change in a series of changes.
           * <p>
           * Repeatedly calling this method allows a listener to fetch all subsequent changes of a bulk
           * set modification that would otherwise be reported as repeated invocations of the listener.
           * If the listener only fetches some of the pending changes, the rest of the changes will be
           * reported with subsequent listener invocations.
           * <p>
           * After this method has been called, the current {@code Change} instance is no longer valid and
           * calling any method on it may result in undefined behavior. Callers must not make any assumptions
           * about the identity of the {@code Change} instance returned by this method; even if the returned
           * instance is the same as the current instance, it must be treated as a distinct change.
           * <p>
           * Since this method must not be called before inspecting the first change, listeners will
           * usually use a do-while loop to iterate over multiple changes:
           * <pre>{@code
           * set.addListener((SetChangeListener<String>) change -> {
           * do {
           * // Inspect the change
           * // ...
           * } while ((change = change.next()) != null);
           * });
           * }</pre>
           *
           * @return the next change, or {@code null} if there are no more changes
           */
           public Change<E> next() { return null; }


      This new method allows listener implementations to fetch all subsequent changes of a bulk operation, which can be implemented as follows:

          set.addListener((SetChangeListener) change -> {
              do {
                  // Inspect the change
                  if (change.wasAdded()) {
                      ...
                  } else if (change.wasRemoved() {
                      ...
                  }
              } while ((change = change.next()) != null);
          }


      The new API is fully backwards-compatible for both producers and listeners of change events. For implementations of ObservableSet or ObservableMap, a failure to override Change.next() means that every listener invocation only communicates a single change. For listeners, if the next() method is not called, then all subsequent changes are delivered as usual by repeated listener invocations.

      If a listener only fetches some changes of a bulk operation (but stops halfway through the operation), the remaining changes must be delivered with repeated listener invocations.

            mstrauss Michael Strauß
            mstrauss Michael Strauß
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated: