code: private boolean applyChange(boolean isChangeAvailable, Supplier<C> changeToApply) {
          if (isChangeAvailable) {
              canMerge = false;
  
              // perform change
              C change = changeToApply.get();
              this.expectedChange = change;
              performingAction.suspendWhile(() -> apply.accept(change));
              if(this.expectedChange != null) {
                  throw new IllegalStateException("Expected change not received:\n"
                          + this.expectedChange);
              }
  
              invalidateProperties();
              return true;
          } else {
              return false;
          }
      }
docs: Helper method for reducing code duplication
  
  @param isChangeAvailable same as `isUndoAvailable()` [Undo] or `isRedoAvailable()` [Redo]
  @param changeToApply same as `invert.apply(queue.prev())` [Undo] or `queue.next()` [Redo]