2

The Collection interface in Java has, among others, these methods:

boolean add(E e)
boolean addAll(Collection<? extends E> c)
boolean remove(Object o)
boolean removeAll(Collection<?> c)
default boolean removeIf(Predicate<? super E> filter)
boolean retainAll(Collection<?> c)

Common for these is what they return:

true if this collection changed as a result of the call

Or in more general terms, returns true if the method call caused anything to change, false otherwise.

Does this pattern have a name? I would like to know more about it. I have not seen it much elsewhere.

1
  • My guess is that this is particularly useful in a multithreaded application. If the collection changes, you might want to update a cache, fire an event, etc... I seldom used the return value for that. It is sometimes useful for unit tests.
    – user949300
    Mar 31 at 4:17

2 Answers 2

1

This seems to be a variation on the operation result pattern; but rather shoddily implemented as it falls prey to primitive obsession.

I call it a variation because the return value isn't indicating success, it's indicating change. Not changing something can be a successful outcome of an operation; these two are not inherently synonymous. retainAll is a good example here. If you end up retaining all the original elements; then you've encountered a success but no change.

6
  • Failure is indicated by an exception being raised. Success is assumed.
    – JimmyJames
    Mar 31 at 13:58
  • @JimmyJames: The operation result pattern is often specifically used to avoid what would otherwise be flow by exception when the failure is not an exceptional circumstance.
    – Flater
    Mar 31 at 13:59
  • What would be a non-exceptional circumstance that would cause adding a element to an in-memory data structure e.g.: HashSet?
    – JimmyJames
    Mar 31 at 14:10
  • You could simply argue you don't need to signal success*/*failure in a template collection operation (because most, if not all, of the failure cases can be statically detected at compile time).
    – tofro
    Mar 31 at 15:13
  • One person's blog post doesn't make a pattern. Even the author admits that it's not an "official" pattern, although their definition of "official" (that it appears in a book) is suspect anyway. Mar 31 at 16:59
1

I think calling this a 'pattern' is a stretch. It's really just an approach to interface definition. It's useful in sets, when you have extra steps when something new is encountered: instead of a call to check for membership and then adding to the set, you just call add and check the result. For example, a simple cycle detection solution:

boolean cycleExists(Collection<Node> path) {
    Set<Node> traversed = new HashSet<>();

    for (Node n : path) {
        if (!traversed.add(n)) return true;
    }

    return false;
}

A similar approach is used with Map.put() but instead of returning a boolean, if you update an existing key, it returns the value that was associated with the key prior to the call.

You'll see this used in a lot of the concurrent APIs. For example compareAndSet in AtomicInteger. In that secenario, it's more of a necessity due to the atomic nature of the call.

Not the answer you're looking for? Browse other questions tagged or ask your own question.