Explain Codes LogoExplain Codes Logo

How can I add to List<? extends Number> data structures?

java
generics
collections
best-practices
Alex KataevbyAlex Kataev·Feb 9, 2025
TLDR
List<Number> numbers = new ArrayList<>(); numbers.add(42); // Integer, The Answer to the Ultimate Question of Life, The Universe, and Everything numbers.add(3.14); // Double, because who doesn't like pie... I mean Pi? List<? extends Number> readOnlyNumbers = numbers;

Make a List<Number> to add numbers, then cast as List<? extends Number> for read-only operations. This exploits polymorphism enabling any Number type in a list while preserving type safety.

Circumventing wildcard limitations

The read-only nature of List<? extends Number>

In List<? extends Number>, inserting an item is prohibited because Java can't infer the exact subtype at runtime. Remember this when dealing with the list!

Strategies for adding to the list

Consider using List<Number> or List<? super Number> instead. This allows you flexibility in adding subtypes Number while keeping the benefits of generics.

Copying elements with Collections.copy()

The Collections.copy() method works well with wildcards, allowing the copying of elements from type-compatible lists, helping you navigate tricky generics conditions.

Befriending the super keyword

Flexibility in adding elements

A List<? super Number> allows the addition of any Number subtype. This is handy for writing to a list without being locked to a specific subtype.

List<Object> objects = new ArrayList<>(); List<? super Number> superNumbers = objects; superNumbers.add(42); // "Integer" dons its cape like a real superhero superNumbers.add(3.1415f); // Float, because precision matters

Caveats with super

List<? super T> is fantastic for writing but might cause trouble when reading values as they'll be treated as Object instances — a compromise with its flexibility.

Evading usual snags

Discourage unsafe operations

Steer away from unsafe casts or approach bypassing type checks. Often, these result in runtime errors. Remember, Java enforces type safety!

Declare with precision

Choose List<Number> when intending to manipulate contents. This reduces capture#1-of ? extends Number errors and allows for reading and writing flexibility.

Caution during initialization

You can set elements in List<? extends Number> during initialization. Post this, the list becomes untouchable, locking its type fidelity.