Generics
Java
Type Inference
Data Structures
Programming

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

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

In Java, generics provide a way to enforce type safety in collections. An important aspect of generics is their use with wildcard characters, particularly the use of bounded wildcards, such as List<? extends Number>. This type of wildcard specifies that the list can hold elements of a specific type or any subtype of that type. Here's an examination of how you can interact with such a data structure and why certain operations are limited.

Understanding List<? extends Number>

The <? extends Number> is a bounded wildcard which declares an upper bound, meaning the list can store objects that are of type Number or any subclass thereof, such as Integer, Double, or Float. The wildcard indicates some unknown type that extends Number.

Key Characteristics

  1. Readability: You can retrieve elements from this list safely in the sense that what you retrieve will definitely be a Number or a subclass. So, you can perform operations or methods available in the Number class on retrieved elements.
  2. Write Limitations: You cannot add elements to a List<? extends Number> due to the restrictions of bounded wildcards.

Why Adding Elements is Not Allowed

With List<? extends Number>, the exact type of the list is unspecified beyond it being a subtype of Number. Since the compiler cannot verify what specific Number subtype might be used, it restricts writing operations to prevent type safety violations.

To understand this better, consider:

java
List<? extends Number> numbers = new ArrayList<Integer>();
// numbers.add(2); // This will not compile

The Java compiler prohibits this because it cannot ensure that the list expects an Integer when the wildcard could represent any subclass of Number.

Alternative Solutions

When you need to add elements, you must use a producer-consumer pattern or a more specific typing:

PECS: Producer Extends, Consumer Super

When dealing with generics in Java, the PECS principle helps guide whether to use extends or super. Here, it implies:

  • Use extends when you are producing and do not intend to mutate the data.
  • Use super when consuming or mutating the data.

Example:

java
1// Using super to allow additions
2List<? super Number> numbers = new ArrayList<Number>();
3numbers.add(11); 
4numbers.add(3.14);

By using List<? super Number>, you inform the compiler that the list can accept any object of type Number or any supertype, thereby allowing additions.

When to Use List<?> vs List<? extends Number>

PurposeUse
General consumptionList<?>
Produce numbersList<? extends Number>
Add numbersList<? super Number>
Precise type operationsList<Type> (e.g., List<Integer>)

Example Scenario

Consider a scenario where you're creating a method to sum all numbers in a list:

java
1public double sumNumbers(List<? extends Number> list) {
2    double sum = 0.0;
3    for (Number number : list) {
4        sum += number.doubleValue();
5    }
6    return sum;
7}

This method demonstrates how you can read from a List<? extends Number> efficiently to perform operations such as summation.

Conclusion

Understanding the behavior of bounded wildcards, such as List<? extends Number>, is crucial when designing method signatures and manipulating data structures in Java. The constraints imposed on adding elements serve to maintain type safety and ensure that methods consuming and producing data adhere to specified bounds. For flexibility and adding capabilities, consider using List<? super Number> to allow writing across subtypes of Number. These principles guide the effective use of Java generics, ensuring both flexibility and robustness in type-safe programming.


Course illustration
Course illustration

All Rights Reserved.