code: @SuppressWarnings({"ConstantConditions", "deprecation"})
      @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE")
      public boolean addOrReplaceAction(@Nonnull Action a) {
          if (a == null) {
              throw new IllegalArgumentException("Action must be non-null");
          }
          // CopyOnWriteArrayList does not support Iterator.remove, so need to do it this way:
          List<Action> old = new ArrayList<>(1);
          List<Action> current = getActions();
          boolean found = false;
          for (Action a2 : current) {
              if (!found && a.equals(a2)) {
                  found = true;
              } else  if (a2.getClass() == a.getClass()) {
                  old.add(a2);
              }
          }
          current.removeAll(old);
          if (!found) {
              addAction(a);
          }
          return !found || !old.isEmpty();
      }
docs: Add an action, replacing any existing actions of the (exact) same class.
  Note: calls to {@link #getAllActions()} that happen before calls to this method may not see the update.
  Note: this method does not affect transient actions contributed by a {@link TransientActionFactory}
  Note: this method cannot provide concurrency control due to the backing storage being a
  {@link CopyOnWriteArrayList} so concurrent calls to any of the mutation methods may produce surprising results
  though technically consistent from the concurrency contract of {@link CopyOnWriteArrayList} (we would need
  some form of transactions or a different backing type).
  
  @param a an action to add/replace
  @return {@code true} if this actions changed as a result of the call
  @since 2.29