Java UnsupportedOperationException

An UnsupportedOperationException is thrown when an operation is performed on an object that does not support it. It is most commonly encountered with collections — particularly unmodifiable or fixed-size lists returned by factory methods like Arrays.asList(), List.of(), or Collections.unmodifiableList().

Common Causes

// Cause 1: Trying to add to Arrays.asList() result
List<String> list = Arrays.asList("a", "b");
list.add("c");  // UnsupportedOperationException

// Cause 2: Trying to add to List.of() (Java 9+ immutable)
List<String> immutable = List.of("x", "y");
immutable.add("z");  // UnsupportedOperationException

// Cause 3: Trying to modify an unmodifiable wrapper
List<String> wrapped = Collections.unmodifiableList(new ArrayList<>());
wrapped.add("item");  // UnsupportedOperationException

// Cause 4: Calling reduce on a Stream without identity
Stream<Integer> stream = Stream.of(1, 2, 3);
stream.reduce((a, b) -> a + b).get();  // works, but reduce on parallel
// streams may throw if no combiner

Solutions

Fix 1: Use a mutable collection type from the start

// Wrong — Arrays.asList returns a fixed-size list
List<String> list = Arrays.asList("a", "b");
list.add("c");  // UnsupportedOperationException

// Correct — wrap in ArrayList for full mutability
List<String> list = new ArrayList<>(Arrays.asList("a", "b"));
list.add("c");  // works fine

// Correct — build with List.of then wrap (Java 9+)
List<String> list = new ArrayList<>(List.of("a", "b"));
list.add("c");

Fix 2: Understand what each factory method returns

// Fixed-size list — can set(), but not add()/remove()
List<String> fixed = Arrays.asList("a", "b");
fixed.set(0, "x");  // works
fixed.add("c");      // UnsupportedOperationException

// Truly immutable — cannot modify at all
List<String> immutable = List.of("a", "b");
immutable.set(0, "x");  // UnsupportedOperationException
immutable.add("c");      // UnsupportedOperationException

Fix 3: Copy unmodifiable collections before modifying

List<String> config = Collections.unmodifiableList(getConfigValues());

// Wrong — modifying the unmodifiable wrapper
config.add("extra");

// Correct — copy to a mutable list first
List<String> mutableConfig = new ArrayList<>(config);
mutableConfig.add("extra");

Fix 4: Implement the method if you extend an abstract class

import java.util.AbstractList;

public class SinglyLinkedList<E> extends AbstractList<E> {
    private final List<E> data = new ArrayList<>();

    @Override
    public E get(int index) {
        return data.get(index);
    }

    @Override
    public int size() {
        return data.size();
    }

    // Optional: override add() if you want add() to work
    @Override
    public boolean add(E element) {
        return data.add(element);
    }
}

// Without overriding add(), add() throws UnsupportedOperationException

Fix 5: Use List.copyOf() for truly immutable snapshots (Java 10+)

List<String> mutable = new ArrayList<>(Arrays.asList("a", "b"));
List<String> snapshot = List.copyOf(mutable);

// snapshot is immutable — no mutation methods work
// Use this when you intentionally want an unmodifiable view

Prevention Tips

  • Know the difference between Arrays.asList() (fixed-size), List.of() (immutable), and new ArrayList<>() (mutable)
  • When returning collections from methods, decide intentionally whether callers should be able to modify them
  • Document whether your method returns an unmodifiable view or a copy
  • Use Collections.unmodifiableList() when exposing internal state to prevent accidental modification

Comments