Your method accepts List<Number> but caller has List<Integer>. It won't compile - generics aren't covariant. Wildcards like List<? extends Number> accept List of any Number subtype, enabling flexible APIs.

Unbounded wildcard

Accept any type.

intSearch
Unbounded.java
Replay: real traced execution (multi-file project)
import java.util.*;

public class Unbounded {
    public static void printList(List<?> list) {
        System.out.print("  List: [");
        for (int i = 0; i < list.size(); i++) {
            if (i > 0) System.out.print(", ");
            System.out.print(list.get(i));
        }
        System.out.println("]");
    }

    public static void main(String[] args) {
        System.out.println("Unbounded wildcard:\n");

        List<Integer> ints = Arrays.asList(1, 2, 3);
        List<String> strs = Arrays.asList("a", "b", "c");
        List<Double> doubles = Arrays.asList(1.1, 2.2, 3.3);

        printList(ints);
        printList(strs);
        printList(doubles);

        // <?> means "list of unknown type"
        // Can read elements as Object
        // Cannot add elements (except null)
        // Useful for methods that only read

        System.out.println("\nSize check:");

        class Utils {
            public static int getSize(List<?> list) {
                return list.size();
            }

            public static boolean isEmpty(List<?> list) {
                return list.isEmpty();
            }
        }

        System.out.println("  Size of ints: " + Utils.getSize(ints));
        System.out.println("  Size of strs: " + Utils.getSize(strs));
        System.out.println("  Empty: " + Utils.isEmpty(new ArrayList<>()));

        System.out.println("\nClear list:");

        class Clearer {
            public static void clear(List<?> list) {
                list.clear();
                System.out.println("  List cleared, size: " + list.size());
            }
        }

        List<String> temp = new ArrayList<>(Arrays.asList("x", "y", "z"));
        System.out.println("  Before: " + temp);
        Clearer.clear(temp);
        System.out.println("  After: " + temp);

        System.out.println("\nContains check:");

        class Checker {
            public static boolean contains(List<?> list, Object item) {
                return list.contains(item);
            }

            public static void displayFirst(List<?> list) {
                if (!list.isEmpty()) {
                    Object first = list.get(0);  // Read as Object
                    System.out.println("  First: " + first);
                }
            }
        }

        int intSearch = 2;
        System.out.println("  ints contains " + intSearch + ": " +
                         Checker.contains(ints, intSearch));
        System.out.println("  strs contains 'x': " + Checker.contains(strs, "x"));

        Checker.displayFirst(ints);
        Checker.displayFirst(strs);

        System.out.println("\nCopy to Object list:");

        class Copier {
            public static List<Object> toObjectList(List<?> source) {
                List<Object> result = new ArrayList<>();
                for (Object item : source) {  // Can read as Object
                    result.add(item);
                }
                return result;
            }
        }

        List<Integer> numbers = Arrays.asList(10, 20, 30);
        List<Object> objects = Copier.toObjectList(numbers);
        System.out.println("  Copied: " + objects);

        System.out.println("\nLimitations:");

        List<?> wildList = new ArrayList<String>();
        // wildList.add("text");  // Compile error - can't add
        // wildList.add(123);     // Compile error - can't add
        wildList.add(null);      // Only null allowed

        System.out.println("  Can only add null to List<?>");
        System.out.println("  Size: " + wildList.size());
    }
}
import java.util.*;

public class Unbounded {
    public static void printList(List<?> list) {
        System.out.print("  List: [");
        for (int i = 0; i < list.size(); i++) {
            if (i > 0) System.out.print(", ");
            System.out.print(list.get(i));
        }
        System.out.println("]");
    }

    public static void main(String[] args) {
        System.out.println("Unbounded wildcard:\n");

        List<Integer> ints = Arrays.asList(1, 2, 3);
        List<String> strs = Arrays.asList("a", "b", "c");
        List<Double> doubles = Arrays.asList(1.1, 2.2, 3.3);

        printList(ints);
        printList(strs);
        printList(doubles);

        // <?> means "list of unknown type"
        // Can read elements as Object
        // Cannot add elements (except null)
        // Useful for methods that only read

        System.out.println("\nSize check:");

        class Utils {
            public static int getSize(List<?> list) {
                return list.size();
            }

            public static boolean isEmpty(List<?> list) {
                return list.isEmpty();
            }
        }

        System.out.println("  Size of ints: " + Utils.getSize(ints));
        System.out.println("  Size of strs: " + Utils.getSize(strs));
        System.out.println("  Empty: " + Utils.isEmpty(new ArrayList<>()));

        System.out.println("\nClear list:");

        class Clearer {
            public static void clear(List<?> list) {
                list.clear();
                System.out.println("  List cleared, size: " + list.size());
            }
        }

        List<String> temp = new ArrayList<>(Arrays.asList("x", "y", "z"));
        System.out.println("  Before: " + temp);
        Clearer.clear(temp);
        System.out.println("  After: " + temp);

        System.out.println("\nContains check:");

        class Checker {
            public static boolean contains(List<?> list, Object item) {
                return list.contains(item);
            }

            public static void displayFirst(List<?> list) {
                if (!list.isEmpty()) {
                    Object first = list.get(0);  // Read as Object
                    System.out.println("  First: " + first);
                }
            }
        }

        int intSearch = 1;
        System.out.println("  ints contains " + intSearch + ": " +
                         Checker.contains(ints, intSearch));
        System.out.println("  strs contains 'x': " + Checker.contains(strs, "x"));

        Checker.displayFirst(ints);
        Checker.displayFirst(strs);

        System.out.println("\nCopy to Object list:");

        class Copier {
            public static List<Object> toObjectList(List<?> source) {
                List<Object> result = new ArrayList<>();
                for (Object item : source) {  // Can read as Object
                    result.add(item);
                }
                return result;
            }
        }

        List<Integer> numbers = Arrays.asList(10, 20, 30);
        List<Object> objects = Copier.toObjectList(numbers);
        System.out.println("  Copied: " + objects);

        System.out.println("\nLimitations:");

        List<?> wildList = new ArrayList<String>();
        // wildList.add("text");  // Compile error - can't add
        // wildList.add(123);     // Compile error - can't add
        wildList.add(null);      // Only null allowed

        System.out.println("  Can only add null to List<?>");
        System.out.println("  Size: " + wildList.size());
    }
}
import java.util.*;

public class Unbounded {
    public static void printList(List<?> list) {
        System.out.print("  List: [");
        for (int i = 0; i < list.size(); i++) {
            if (i > 0) System.out.print(", ");
            System.out.print(list.get(i));
        }
        System.out.println("]");
    }

    public static void main(String[] args) {
        System.out.println("Unbounded wildcard:\n");

        List<Integer> ints = Arrays.asList(1, 2, 3);
        List<String> strs = Arrays.asList("a", "b", "c");
        List<Double> doubles = Arrays.asList(1.1, 2.2, 3.3);

        printList(ints);
        printList(strs);
        printList(doubles);

        // <?> means "list of unknown type"
        // Can read elements as Object
        // Cannot add elements (except null)
        // Useful for methods that only read

        System.out.println("\nSize check:");

        class Utils {
            public static int getSize(List<?> list) {
                return list.size();
            }

            public static boolean isEmpty(List<?> list) {
                return list.isEmpty();
            }
        }

        System.out.println("  Size of ints: " + Utils.getSize(ints));
        System.out.println("  Size of strs: " + Utils.getSize(strs));
        System.out.println("  Empty: " + Utils.isEmpty(new ArrayList<>()));

        System.out.println("\nClear list:");

        class Clearer {
            public static void clear(List<?> list) {
                list.clear();
                System.out.println("  List cleared, size: " + list.size());
            }
        }

        List<String> temp = new ArrayList<>(Arrays.asList("x", "y", "z"));
        System.out.println("  Before: " + temp);
        Clearer.clear(temp);
        System.out.println("  After: " + temp);

        System.out.println("\nContains check:");

        class Checker {
            public static boolean contains(List<?> list, Object item) {
                return list.contains(item);
            }

            public static void displayFirst(List<?> list) {
                if (!list.isEmpty()) {
                    Object first = list.get(0);  // Read as Object
                    System.out.println("  First: " + first);
                }
            }
        }

        int intSearch = 4;
        System.out.println("  ints contains " + intSearch + ": " +
                         Checker.contains(ints, intSearch));
        System.out.println("  strs contains 'x': " + Checker.contains(strs, "x"));

        Checker.displayFirst(ints);
        Checker.displayFirst(strs);

        System.out.println("\nCopy to Object list:");

        class Copier {
            public static List<Object> toObjectList(List<?> source) {
                List<Object> result = new ArrayList<>();
                for (Object item : source) {  // Can read as Object
                    result.add(item);
                }
                return result;
            }
        }

        List<Integer> numbers = Arrays.asList(10, 20, 30);
        List<Object> objects = Copier.toObjectList(numbers);
        System.out.println("  Copied: " + objects);

        System.out.println("\nLimitations:");

        List<?> wildList = new ArrayList<String>();
        // wildList.add("text");  // Compile error - can't add
        // wildList.add(123);     // Compile error - can't add
        wildList.add(null);      // Only null allowed

        System.out.println("  Can only add null to List<?>");
        System.out.println("  Size: " + wildList.size());
    }
}
  1. public static void main(String[] args)

    13public static void main(String[] args) {14    System.out.println("Unbounded wildcard:\n");
    outputUnbounded wildcard:
    Unbounded wildcard:
  2. public static void printList(List<?> list)

    pass 1 of 3
    3public class Unbounded {4    public static void printList(List<?> list[1, 2, 3]) {5        System.out.print("  List: [");6        for (int i = 0; i < list.size(); i++) {
    output  List: [
    All 3 passes — pass 1 is the card above
    passlist
    1[1, 2, 3]
    2[a, b, c]
    3[1.1, 2.2, 3.3]
  3. for (int i = 0; i < list.size(); i++)

    pass 1 of 9
    5System.out.print("  List: [");6for (int i0 = 0; i < list.size(); i++) {7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i0));9}
    output1
    All 9 passes — pass 1 is the card above
    passi
    10
    21
    32
    40
    51
    62
    70
    81
    92
  4. if (i > 0)

    pass 1 of 6
    6for (int i = 0; i < list.size(); i++) {7    if (i1 > 0) System.out.print(", ");8    System.out.print(list.get(i));
    output, 
    All 6 passes — pass 1 is the card above
    passi
    11
    22
    31
    42
    51
    62
  5. System.out.print(list.get(i));

    7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i1));9}
    output2
  6. System.out.print(list.get(i));

    7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i2));9}
    output3
  7. System.out.println("]");

    9    }10    System.out.println("]");11}
    output]
  8. System.out.print(list.get(i));

    7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i1));9}
    outputb
  9. System.out.print(list.get(i));

    7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i2));9}
    outputc
  10. System.out.println("]");

    9    }10    System.out.println("]");11}
    output]
  11. System.out.print(list.get(i));

    7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i1));9}
    output2.2
  12. System.out.print(list.get(i));

    7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i2));9}
    output3.3
  13. System.out.println("]");

    9    }10    System.out.println("]");11}
    output]
  14. System.out.println(" Size check:");

    29System.out.println("\nSize check:");
    output
    Size check:
    
    Size check:
  15. public static int getSize(List<?> list)

    pass 1 of 3
    31class Utils {32    public static int getSize(List<?> list[1, 2, 3]) {33        return list.size();34    }
    All 3 passes — pass 1 is the card above
    passlist
    1[1, 2, 3]
    2[a, b, c]
    3[a, b, c]
  16. System.out.println(" Size of strs: " + Utils.getSize(strs));

    41System.out.println("  Size of ints: " + Utils.getSize(ints));42System.out.println("  Size of strs: " + Utils.getSize(strs[a, b, c]));43System.out.println("  Empty: " + Utils.isEmpty(new ArrayList<>()));
  17. System.out.println(" Size of strs: " + Utils.getSize(strs));

    41System.out.println("  Size of ints: " + Utils.getSize(ints));42System.out.println("  Size of strs: " + Utils.getSize(strs[a, b, c]));43System.out.println("  Empty: " + Utils.isEmpty(new ArrayList<>()));
    output  Size of strs: 3
  18. System.out.println(" Size of strs: " + Utils.getSize(strs));

    41System.out.println("  Size of ints: " + Utils.getSize(ints));42System.out.println("  Size of strs: " + Utils.getSize(strs[a, b, c]));43System.out.println("  Empty: " + Utils.isEmpty(new ArrayList<>()));
    output  Size of strs: 3
  19. public static boolean isEmpty(List<?> list)

    pass 1 of 2
    36public static boolean isEmpty(List<?> list[]) {37    return list.isEmpty();38}
  20. System.out.println(" Empty: " + Utils.isEmpty(new ArrayList<>()));

    42System.out.println("  Size of strs: " + Utils.getSize(strs));43System.out.println("  Empty: " + Utils.isEmpty(new ArrayList<>()));
    output  Empty: true
  21. public static boolean isEmpty(List<?> list)

    pass 2 of 2
    36public static boolean isEmpty(List<?> list[]) {37    return list.isEmpty();38}
  22. System.out.println(" Before: " + temp);

    42System.out.println("  Size of strs: " + Utils.getSize(strs));43System.out.println("  Empty: " + Utils.isEmpty(new ArrayList<>()));4445System.out.println("\nClear list:");4647class Clearer {48    public static void clear(List<?> list) {49        list.clear();50        System.out.println("  List cleared, size: " + list.size());51    }52}5354List<String> temp = new ArrayList<>(Arrays.asList("x", "y", "z"));55System.out.println("  Before: " + temp[x, y, z]);56Clearer.clear(temp);
    output  Empty: true
    
    Clear list:
    
    Clear list:
      Before: [x, y, z]
      Before: [x, y, z]
  23. public static void clear(List<?> list)

    47class Clearer {48    public static void clear(List<?> list[x, y, z]) {49        list.clear();50        System.out.println("  List cleared, size: " + list.size());51    }
    output  List cleared, size: 0
  24. System.out.println(" After: " + temp);

    56Clearer.clear(temp);57System.out.println("  After: " + temp[]);5859System.out.println("\nContains check:");6061class Checker {62    public static boolean contains(List<?> list, Object item) {63        return list.contains(item);64    }65    66    public static void displayFirst(List<?> list) {67        if (!list.isEmpty()) {68            Object first = list.get(0);  // Read as Object69            System.out.println("  First: " + first);70        }71    }72}7374int intSearch = 2; //@intSearch=2, 1, 475System.out.println("  ints contains " + intSearch2 + ": " +76                 Checker.contains(ints[1, 2, 3], intSearch2));77System.out.println("  strs contains 'x': " + Checker.contains(strs, "x"));
    output  After: []
      After: []
    
    Contains check:
    
    Contains check:
  25. public static boolean contains(List<?> list, Object item)

    pass 1 of 4
    61class Checker {62    public static boolean contains(List<?> list[1, 2, 3], Object item2) {63        return list.contains(item2);64    }
    All 4 passes — pass 1 is the card above
    passlistitem
    1[1, 2, 3]2
    2[1, 2, 3]2
    3[a, b, c]x
    4[a, b, c]x
  26. System.out.println(" ints contains " + intSearch + ": " +

    74int intSearch = 2; //@intSearch=2, 1, 475System.out.println("  ints contains " + intSearch2 + ": " +76                 Checker.contains(ints[1, 2, 3], intSearch2));77System.out.println("  strs contains 'x': " + Checker.contains(strs, "x"));
    output  ints contains 2: true
  27. System.out.println(" ints contains " + intSearch + ": " +

    74int intSearch = 2; //@intSearch=2, 1, 475System.out.println("  ints contains " + intSearch2 + ": " +76                 Checker.contains(ints[1, 2, 3], intSearch2));77System.out.println("  strs contains 'x': " + Checker.contains(strs[a, b, c], "x"));
    output  ints contains 2: true
  28. System.out.println(" strs contains 'x': " + Checker.contains(strs, "x…

    76                 Checker.contains(ints, intSearch));77System.out.println("  strs contains 'x': " + Checker.contains(strs[a, b, c], "x"));
    output  strs contains 'x': false
  29. System.out.println(" strs contains 'x': " + Checker.contains(strs, "x…

    76                 Checker.contains(ints, intSearch));77System.out.println("  strs contains 'x': " + Checker.contains(strs[a, b, c], "x"));
    output  strs contains 'x': false
  30. public static void displayFirst(List<?> list)

    pass 1 of 2
    66public static void displayFirst(List<?> list[1, 2, 3]) {67    if (!list.isEmpty()) {
  31. first ← 1

    pass 1 of 2
    66public static void displayFirst(List<?> list) {67    if (!list.isEmpty()) {68        Object first→ 1 = list.get(0);  // Read as Object69        System.out.println("  First: " + first1);70    }
    output  First: 1
  32. public static void displayFirst(List<?> list)

    pass 2 of 2
    66public static void displayFirst(List<?> list[a, b, c]) {67    if (!list.isEmpty()) {
  33. first ← a

    pass 2 of 2
    66public static void displayFirst(List<?> list) {67    if (!list.isEmpty()) {68        Object first→ a = list.get(0);  // Read as Object69        System.out.println("  First: " + firsta);70    }
    output  First: a
  34. List<Object> objects = Copier.toObjectList(numbers);

    82System.out.println("\nCopy to Object list:");8384class Copier {85    public static List<Object> toObjectList(List<?> source) {86        List<Object> result = new ArrayList<>();87        for (Object item : source) {  // Can read as Object88            result.add(item);89        }90        return result;91    }92}9394List<Integer> numbers = Arrays.asList(10, 20, 30);95List<Object> objects = Copier.toObjectList(numbers[10, 20, 30]);96System.out.println("  Copied: " + objects);
    output
    Copy to Object list:
    
    Copy to Object list:
  35. result ← []

    84class Copier {85    public static List<Object> toObjectList(List<?> source[10, 20, 30]) {86        List<Object> result→ [] = new ArrayList<>();87        for (Object item : source) {  // Can read as Object
  36. for (Object item : source)

    pass 1 of 3
    86List<Object> result = new ArrayList<>();87for (Object item10 : source[10, 20, 30]) {  // Can read as Object88    result.add(item10);89}
    All 3 passes — pass 1 is the card above
    passitem
    110
    220
    330
  37. return result;

    89    }90    return result[10, 20, 30];91}
  38. objects ← [10, 20, 30], wildList ← []

    94    List<Integer> numbers = Arrays.asList(10, 20, 30);95    List<Object> objects→ [10, 20, 30] = Copier.toObjectList(numbers[10, 20, 30]);96    System.out.println("  Copied: " + objects[10, 20, 30]);97    98    System.out.println("\nLimitations:");99    100    List<?> wildList→ [] = new ArrayList<String>();101    // wildList.add("text");  // Compile error - can't add102    // wildList.add(123);     // Compile error - can't add103    wildList.add(null);      // Only null allowed104    105    System.out.println("  Can only add null to List<?>");106    System.out.println("  Size: " + wildList.size());107}
    output  Copied: [10, 20, 30]
    
    Limitations:
      Can only add null to List<?>
      Size: 1
  1. public static void main(String[] args)

    13public static void main(String[] args) {14    System.out.println("Unbounded wildcard:\n");
    outputUnbounded wildcard:
    Unbounded wildcard:
  2. public static void printList(List<?> list)

    pass 1 of 3
    3public class Unbounded {4    public static void printList(List<?> list[1, 2, 3]) {5        System.out.print("  List: [");6        for (int i = 0; i < list.size(); i++) {
    output  List: [
    All 3 passes — pass 1 is the card above
    passlist
    1[1, 2, 3]
    2[a, b, c]
    3[1.1, 2.2, 3.3]
  3. for (int i = 0; i < list.size(); i++)

    pass 1 of 9
    5System.out.print("  List: [");6for (int i0 = 0; i < list.size(); i++) {7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i0));9}
    output1
    All 9 passes — pass 1 is the card above
    passi
    10
    21
    32
    40
    51
    62
    70
    81
    92
  4. if (i > 0)

    pass 1 of 6
    6for (int i = 0; i < list.size(); i++) {7    if (i1 > 0) System.out.print(", ");8    System.out.print(list.get(i));
    output, 
    All 6 passes — pass 1 is the card above
    passi
    11
    22
    31
    42
    51
    62
  5. System.out.print(list.get(i));

    7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i1));9}
    output2
  6. System.out.print(list.get(i));

    7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i2));9}
    output3
  7. System.out.println("]");

    9    }10    System.out.println("]");11}
    output]
  8. System.out.print(list.get(i));

    7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i1));9}
    outputb
  9. System.out.print(list.get(i));

    7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i2));9}
    outputc
  10. System.out.println("]");

    9    }10    System.out.println("]");11}
    output]
  11. System.out.print(list.get(i));

    7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i1));9}
    output2.2
  12. System.out.print(list.get(i));

    7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i2));9}
    output3.3
  13. System.out.println("]");

    9    }10    System.out.println("]");11}
    output]
  14. System.out.println(" Size check:");

    29System.out.println("\nSize check:");
    output
    Size check:
    
    Size check:
  15. public static int getSize(List<?> list)

    pass 1 of 3
    31class Utils {32    public static int getSize(List<?> list[1, 2, 3]) {33        return list.size();34    }
    All 3 passes — pass 1 is the card above
    passlist
    1[1, 2, 3]
    2[a, b, c]
    3[a, b, c]
  16. System.out.println(" Size of strs: " + Utils.getSize(strs));

    41System.out.println("  Size of ints: " + Utils.getSize(ints));42System.out.println("  Size of strs: " + Utils.getSize(strs[a, b, c]));43System.out.println("  Empty: " + Utils.isEmpty(new ArrayList<>()));
  17. System.out.println(" Size of strs: " + Utils.getSize(strs));

    41System.out.println("  Size of ints: " + Utils.getSize(ints));42System.out.println("  Size of strs: " + Utils.getSize(strs[a, b, c]));43System.out.println("  Empty: " + Utils.isEmpty(new ArrayList<>()));
    output  Size of strs: 3
  18. System.out.println(" Size of strs: " + Utils.getSize(strs));

    41System.out.println("  Size of ints: " + Utils.getSize(ints));42System.out.println("  Size of strs: " + Utils.getSize(strs[a, b, c]));43System.out.println("  Empty: " + Utils.isEmpty(new ArrayList<>()));
    output  Size of strs: 3
  19. public static boolean isEmpty(List<?> list)

    pass 1 of 2
    36public static boolean isEmpty(List<?> list[]) {37    return list.isEmpty();38}
  20. System.out.println(" Empty: " + Utils.isEmpty(new ArrayList<>()));

    42System.out.println("  Size of strs: " + Utils.getSize(strs));43System.out.println("  Empty: " + Utils.isEmpty(new ArrayList<>()));
    output  Empty: true
  21. public static boolean isEmpty(List<?> list)

    pass 2 of 2
    36public static boolean isEmpty(List<?> list[]) {37    return list.isEmpty();38}
  22. System.out.println(" Before: " + temp);

    42System.out.println("  Size of strs: " + Utils.getSize(strs));43System.out.println("  Empty: " + Utils.isEmpty(new ArrayList<>()));4445System.out.println("\nClear list:");4647class Clearer {48    public static void clear(List<?> list) {49        list.clear();50        System.out.println("  List cleared, size: " + list.size());51    }52}5354List<String> temp = new ArrayList<>(Arrays.asList("x", "y", "z"));55System.out.println("  Before: " + temp[x, y, z]);56Clearer.clear(temp);
    output  Empty: true
    
    Clear list:
    
    Clear list:
      Before: [x, y, z]
      Before: [x, y, z]
  23. public static void clear(List<?> list)

    47class Clearer {48    public static void clear(List<?> list[x, y, z]) {49        list.clear();50        System.out.println("  List cleared, size: " + list.size());51    }
    output  List cleared, size: 0
  24. System.out.println(" After: " + temp);

    56Clearer.clear(temp);57System.out.println("  After: " + temp[]);5859System.out.println("\nContains check:");6061class Checker {62    public static boolean contains(List<?> list, Object item) {63        return list.contains(item);64    }65    66    public static void displayFirst(List<?> list) {67        if (!list.isEmpty()) {68            Object first = list.get(0);  // Read as Object69            System.out.println("  First: " + first);70        }71    }72}7374int intSearch = 1;75System.out.println("  ints contains " + intSearch1 + ": " +76                 Checker.contains(ints[1, 2, 3], intSearch1));77System.out.println("  strs contains 'x': " + Checker.contains(strs, "x"));
    output  After: []
      After: []
    
    Contains check:
    
    Contains check:
  25. public static boolean contains(List<?> list, Object item)

    pass 1 of 4
    61class Checker {62    public static boolean contains(List<?> list[1, 2, 3], Object item1) {63        return list.contains(item1);64    }
    All 4 passes — pass 1 is the card above
    passlistitem
    1[1, 2, 3]1
    2[1, 2, 3]1
    3[a, b, c]x
    4[a, b, c]x
  26. System.out.println(" ints contains " + intSearch + ": " +

    74int intSearch = 1;75System.out.println("  ints contains " + intSearch1 + ": " +76                 Checker.contains(ints[1, 2, 3], intSearch1));77System.out.println("  strs contains 'x': " + Checker.contains(strs, "x"));
    output  ints contains 1: true
  27. System.out.println(" ints contains " + intSearch + ": " +

    74int intSearch = 1;75System.out.println("  ints contains " + intSearch1 + ": " +76                 Checker.contains(ints[1, 2, 3], intSearch1));77System.out.println("  strs contains 'x': " + Checker.contains(strs[a, b, c], "x"));
    output  ints contains 1: true
  28. System.out.println(" strs contains 'x': " + Checker.contains(strs, "x…

    76                 Checker.contains(ints, intSearch));77System.out.println("  strs contains 'x': " + Checker.contains(strs[a, b, c], "x"));
    output  strs contains 'x': false
  29. System.out.println(" strs contains 'x': " + Checker.contains(strs, "x…

    76                 Checker.contains(ints, intSearch));77System.out.println("  strs contains 'x': " + Checker.contains(strs[a, b, c], "x"));
    output  strs contains 'x': false
  30. public static void displayFirst(List<?> list)

    pass 1 of 2
    66public static void displayFirst(List<?> list[1, 2, 3]) {67    if (!list.isEmpty()) {
  31. first ← 1

    pass 1 of 2
    66public static void displayFirst(List<?> list) {67    if (!list.isEmpty()) {68        Object first→ 1 = list.get(0);  // Read as Object69        System.out.println("  First: " + first1);70    }
    output  First: 1
  32. public static void displayFirst(List<?> list)

    pass 2 of 2
    66public static void displayFirst(List<?> list[a, b, c]) {67    if (!list.isEmpty()) {
  33. first ← a

    pass 2 of 2
    66public static void displayFirst(List<?> list) {67    if (!list.isEmpty()) {68        Object first→ a = list.get(0);  // Read as Object69        System.out.println("  First: " + firsta);70    }
    output  First: a
  34. List<Object> objects = Copier.toObjectList(numbers);

    82System.out.println("\nCopy to Object list:");8384class Copier {85    public static List<Object> toObjectList(List<?> source) {86        List<Object> result = new ArrayList<>();87        for (Object item : source) {  // Can read as Object88            result.add(item);89        }90        return result;91    }92}9394List<Integer> numbers = Arrays.asList(10, 20, 30);95List<Object> objects = Copier.toObjectList(numbers[10, 20, 30]);96System.out.println("  Copied: " + objects);
    output
    Copy to Object list:
    
    Copy to Object list:
  35. result ← []

    84class Copier {85    public static List<Object> toObjectList(List<?> source[10, 20, 30]) {86        List<Object> result→ [] = new ArrayList<>();87        for (Object item : source) {  // Can read as Object
  36. for (Object item : source)

    pass 1 of 3
    86List<Object> result = new ArrayList<>();87for (Object item10 : source[10, 20, 30]) {  // Can read as Object88    result.add(item10);89}
    All 3 passes — pass 1 is the card above
    passitem
    110
    220
    330
  37. return result;

    89    }90    return result[10, 20, 30];91}
  38. objects ← [10, 20, 30], wildList ← []

    94    List<Integer> numbers = Arrays.asList(10, 20, 30);95    List<Object> objects→ [10, 20, 30] = Copier.toObjectList(numbers[10, 20, 30]);96    System.out.println("  Copied: " + objects[10, 20, 30]);97    98    System.out.println("\nLimitations:");99    100    List<?> wildList→ [] = new ArrayList<String>();101    // wildList.add("text");  // Compile error - can't add102    // wildList.add(123);     // Compile error - can't add103    wildList.add(null);      // Only null allowed104    105    System.out.println("  Can only add null to List<?>");106    System.out.println("  Size: " + wildList.size());107}
    output  Copied: [10, 20, 30]
    
    Limitations:
      Can only add null to List<?>
      Size: 1
  1. public static void main(String[] args)

    13public static void main(String[] args) {14    System.out.println("Unbounded wildcard:\n");
    outputUnbounded wildcard:
    Unbounded wildcard:
  2. public static void printList(List<?> list)

    pass 1 of 3
    3public class Unbounded {4    public static void printList(List<?> list[1, 2, 3]) {5        System.out.print("  List: [");6        for (int i = 0; i < list.size(); i++) {
    output  List: [
    All 3 passes — pass 1 is the card above
    passlist
    1[1, 2, 3]
    2[a, b, c]
    3[1.1, 2.2, 3.3]
  3. for (int i = 0; i < list.size(); i++)

    pass 1 of 9
    5System.out.print("  List: [");6for (int i0 = 0; i < list.size(); i++) {7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i0));9}
    output1
    All 9 passes — pass 1 is the card above
    passi
    10
    21
    32
    40
    51
    62
    70
    81
    92
  4. if (i > 0)

    pass 1 of 6
    6for (int i = 0; i < list.size(); i++) {7    if (i1 > 0) System.out.print(", ");8    System.out.print(list.get(i));
    output, 
    All 6 passes — pass 1 is the card above
    passi
    11
    22
    31
    42
    51
    62
  5. System.out.print(list.get(i));

    7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i1));9}
    output2
  6. System.out.print(list.get(i));

    7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i2));9}
    output3
  7. System.out.println("]");

    9    }10    System.out.println("]");11}
    output]
  8. System.out.print(list.get(i));

    7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i1));9}
    outputb
  9. System.out.print(list.get(i));

    7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i2));9}
    outputc
  10. System.out.println("]");

    9    }10    System.out.println("]");11}
    output]
  11. System.out.print(list.get(i));

    7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i1));9}
    output2.2
  12. System.out.print(list.get(i));

    7    if (i > 0) System.out.print(", ");8    System.out.print(list.get(i2));9}
    output3.3
  13. System.out.println("]");

    9    }10    System.out.println("]");11}
    output]
  14. System.out.println(" Size check:");

    29System.out.println("\nSize check:");
    output
    Size check:
    
    Size check:
  15. public static int getSize(List<?> list)

    pass 1 of 3
    31class Utils {32    public static int getSize(List<?> list[1, 2, 3]) {33        return list.size();34    }
    All 3 passes — pass 1 is the card above
    passlist
    1[1, 2, 3]
    2[a, b, c]
    3[a, b, c]
  16. System.out.println(" Size of strs: " + Utils.getSize(strs));

    41System.out.println("  Size of ints: " + Utils.getSize(ints));42System.out.println("  Size of strs: " + Utils.getSize(strs[a, b, c]));43System.out.println("  Empty: " + Utils.isEmpty(new ArrayList<>()));
  17. System.out.println(" Size of strs: " + Utils.getSize(strs));

    41System.out.println("  Size of ints: " + Utils.getSize(ints));42System.out.println("  Size of strs: " + Utils.getSize(strs[a, b, c]));43System.out.println("  Empty: " + Utils.isEmpty(new ArrayList<>()));
    output  Size of strs: 3
  18. System.out.println(" Size of strs: " + Utils.getSize(strs));

    41System.out.println("  Size of ints: " + Utils.getSize(ints));42System.out.println("  Size of strs: " + Utils.getSize(strs[a, b, c]));43System.out.println("  Empty: " + Utils.isEmpty(new ArrayList<>()));
    output  Size of strs: 3
  19. public static boolean isEmpty(List<?> list)

    pass 1 of 2
    36public static boolean isEmpty(List<?> list[]) {37    return list.isEmpty();38}
  20. System.out.println(" Empty: " + Utils.isEmpty(new ArrayList<>()));

    42System.out.println("  Size of strs: " + Utils.getSize(strs));43System.out.println("  Empty: " + Utils.isEmpty(new ArrayList<>()));
    output  Empty: true
  21. public static boolean isEmpty(List<?> list)

    pass 2 of 2
    36public static boolean isEmpty(List<?> list[]) {37    return list.isEmpty();38}
  22. System.out.println(" Before: " + temp);

    42System.out.println("  Size of strs: " + Utils.getSize(strs));43System.out.println("  Empty: " + Utils.isEmpty(new ArrayList<>()));4445System.out.println("\nClear list:");4647class Clearer {48    public static void clear(List<?> list) {49        list.clear();50        System.out.println("  List cleared, size: " + list.size());51    }52}5354List<String> temp = new ArrayList<>(Arrays.asList("x", "y", "z"));55System.out.println("  Before: " + temp[x, y, z]);56Clearer.clear(temp);
    output  Empty: true
    
    Clear list:
    
    Clear list:
      Before: [x, y, z]
      Before: [x, y, z]
  23. public static void clear(List<?> list)

    47class Clearer {48    public static void clear(List<?> list[x, y, z]) {49        list.clear();50        System.out.println("  List cleared, size: " + list.size());51    }
    output  List cleared, size: 0
  24. System.out.println(" After: " + temp);

    56Clearer.clear(temp);57System.out.println("  After: " + temp[]);5859System.out.println("\nContains check:");6061class Checker {62    public static boolean contains(List<?> list, Object item) {63        return list.contains(item);64    }65    66    public static void displayFirst(List<?> list) {67        if (!list.isEmpty()) {68            Object first = list.get(0);  // Read as Object69            System.out.println("  First: " + first);70        }71    }72}7374int intSearch = 4;75System.out.println("  ints contains " + intSearch4 + ": " +76                 Checker.contains(ints[1, 2, 3], intSearch4));77System.out.println("  strs contains 'x': " + Checker.contains(strs, "x"));
    output  After: []
      After: []
    
    Contains check:
    
    Contains check:
  25. public static boolean contains(List<?> list, Object item)

    pass 1 of 4
    61class Checker {62    public static boolean contains(List<?> list[1, 2, 3], Object item4) {63        return list.contains(item4);64    }
    All 4 passes — pass 1 is the card above
    passlistitem
    1[1, 2, 3]4
    2[1, 2, 3]4
    3[a, b, c]x
    4[a, b, c]x
  26. System.out.println(" ints contains " + intSearch + ": " +

    74int intSearch = 4;75System.out.println("  ints contains " + intSearch4 + ": " +76                 Checker.contains(ints[1, 2, 3], intSearch4));77System.out.println("  strs contains 'x': " + Checker.contains(strs, "x"));
    output  ints contains 4: false
  27. System.out.println(" ints contains " + intSearch + ": " +

    74int intSearch = 4;75System.out.println("  ints contains " + intSearch4 + ": " +76                 Checker.contains(ints[1, 2, 3], intSearch4));77System.out.println("  strs contains 'x': " + Checker.contains(strs[a, b, c], "x"));
    output  ints contains 4: false
  28. System.out.println(" strs contains 'x': " + Checker.contains(strs, "x…

    76                 Checker.contains(ints, intSearch));77System.out.println("  strs contains 'x': " + Checker.contains(strs[a, b, c], "x"));
    output  strs contains 'x': false
  29. System.out.println(" strs contains 'x': " + Checker.contains(strs, "x…

    76                 Checker.contains(ints, intSearch));77System.out.println("  strs contains 'x': " + Checker.contains(strs[a, b, c], "x"));
    output  strs contains 'x': false
  30. public static void displayFirst(List<?> list)

    pass 1 of 2
    66public static void displayFirst(List<?> list[1, 2, 3]) {67    if (!list.isEmpty()) {
  31. first ← 1

    pass 1 of 2
    66public static void displayFirst(List<?> list) {67    if (!list.isEmpty()) {68        Object first→ 1 = list.get(0);  // Read as Object69        System.out.println("  First: " + first1);70    }
    output  First: 1
  32. public static void displayFirst(List<?> list)

    pass 2 of 2
    66public static void displayFirst(List<?> list[a, b, c]) {67    if (!list.isEmpty()) {
  33. first ← a

    pass 2 of 2
    66public static void displayFirst(List<?> list) {67    if (!list.isEmpty()) {68        Object first→ a = list.get(0);  // Read as Object69        System.out.println("  First: " + firsta);70    }
    output  First: a
  34. List<Object> objects = Copier.toObjectList(numbers);

    82System.out.println("\nCopy to Object list:");8384class Copier {85    public static List<Object> toObjectList(List<?> source) {86        List<Object> result = new ArrayList<>();87        for (Object item : source) {  // Can read as Object88            result.add(item);89        }90        return result;91    }92}9394List<Integer> numbers = Arrays.asList(10, 20, 30);95List<Object> objects = Copier.toObjectList(numbers[10, 20, 30]);96System.out.println("  Copied: " + objects);
    output
    Copy to Object list:
    
    Copy to Object list:
  35. result ← []

    84class Copier {85    public static List<Object> toObjectList(List<?> source[10, 20, 30]) {86        List<Object> result→ [] = new ArrayList<>();87        for (Object item : source) {  // Can read as Object
  36. for (Object item : source)

    pass 1 of 3
    86List<Object> result = new ArrayList<>();87for (Object item10 : source[10, 20, 30]) {  // Can read as Object88    result.add(item10);89}
    All 3 passes — pass 1 is the card above
    passitem
    110
    220
    330
  37. return result;

    89    }90    return result[10, 20, 30];91}
  38. objects ← [10, 20, 30], wildList ← []

    94    List<Integer> numbers = Arrays.asList(10, 20, 30);95    List<Object> objects→ [10, 20, 30] = Copier.toObjectList(numbers[10, 20, 30]);96    System.out.println("  Copied: " + objects[10, 20, 30]);97    98    System.out.println("\nLimitations:");99    100    List<?> wildList→ [] = new ArrayList<String>();101    // wildList.add("text");  // Compile error - can't add102    // wildList.add(123);     // Compile error - can't add103    wildList.add(null);      // Only null allowed104    105    System.out.println("  Can only add null to List<?>");106    System.out.println("  Size: " + wildList.size());107}
    output  Copied: [10, 20, 30]
    
    Limitations:
      Can only add null to List<?>
      Size: 1

List<?> accepts List of any type. Can only read as Object.

unbounded wildcard `<?>` matches any type. Read-only for practical purposes.

Upper bounded wildcard

Accept type or subtypes.

UpperBound.java
Replay: real traced execution (multi-file project)
import java.util.*;

public class UpperBound {
    public static double sum(List<? extends Number> numbers) {
        double total = 0;
        for (Number num : numbers) {  // Can read as Number
            total += num.doubleValue();
        }
        return total;
    }

    public static void main(String[] args) {
        System.out.println("Upper bounded wildcard:\n");

        List<Integer> ints = Arrays.asList(1, 2, 3, 4, 5);
        List<Double> doubles = Arrays.asList(1.5, 2.5, 3.5);
        List<Long> longs = Arrays.asList(10L, 20L, 30L);

        System.out.println("  Sum ints: " + sum(ints));
        System.out.println("  Sum doubles: " + sum(doubles));
        System.out.println("  Sum longs: " + sum(longs));

        // <? extends T> means "unknown type that extends T"
        // Can read elements as T
        // Cannot add elements (except null) - don't know exact type
        // PECS: Producer Extends - use when reading/producing

        System.out.println("\nFind max:");

        class Finder {
            public static <T extends Comparable<T>> T max(
                    List<? extends T> list) {
                if (list.isEmpty()) {
                    return null;
                }

                T max = list.get(0);
                for (T item : list) {
                    if (item.compareTo(max) > 0) {
                        max = item;
                    }
                }
                return max;
            }
        }

        System.out.println("  Max int: " + Finder.max(ints));
        System.out.println("  Max double: " + Finder.max(doubles));

        List<String> words = Arrays.asList("apple", "zebra", "banana");
        System.out.println("  Max string: " + Finder.max(words));

        System.out.println("\nCopy numbers:");

        class Copier {
            public static void copyNumbers(
                    List<? extends Number> source,
                    List<Number> dest) {
                dest.clear();
                for (Number num : source) {  // Read as Number
                    dest.add(num);
                }
            }
        }

        List<Number> result = new ArrayList<>();
        Copier.copyNumbers(ints, result);
        System.out.println("  Copied: " + result);

        System.out.println("\nAverage:");

        class Stats {
            public static double average(List<? extends Number> numbers) {
                if (numbers.isEmpty()) {
                    return 0;
                }
                return sum(numbers) / numbers.size();
            }

            public static Number min(List<? extends Number> numbers) {
                if (numbers.isEmpty()) {
                    return null;
                }

                double minVal = numbers.get(0).doubleValue();
                Number min = numbers.get(0);

                for (Number num : numbers) {
                    if (num.doubleValue() < minVal) {
                        minVal = num.doubleValue();
                        min = num;
                    }
                }
                return min;
            }
        }

        System.out.println("  Average: " + Stats.average(ints));
        System.out.println("  Min: " + Stats.min(doubles));

        System.out.println("\nPrint comparable:");

        class Printer {
            public static <T extends Comparable<T>> void printSorted(
                    List<? extends T> list) {
                List<T> copy = new ArrayList<>(list);
                Collections.sort(copy);
                System.out.print("  Sorted: ");
                for (T item : copy) {
                    System.out.print(item + " ");
                }
                System.out.println();
            }
        }

        Printer.printSorted(Arrays.asList(5, 1, 9, 3, 7));
        Printer.printSorted(Arrays.asList("dog", "cat", "ant", "bee"));

        System.out.println("\nLimitations:");

        List<? extends Number> numList = new ArrayList<Integer>();
        // numList.add(1);        // Compile error
        // numList.add(1.5);      // Compile error
        // numList.add(new Integer(1));  // Compile error

        System.out.println("  Cannot add to List<? extends Number>");
        System.out.println("  Reason: Don't know if it's Integer, Double, etc.");
    }
}
  1. public static void main(String[] args)

    12public static void main(String[] args) {13    System.out.println("Upper bounded wildcard:\n");14    15    List<Integer> ints = Arrays.asList(1, 2, 3, 4, 5);16    List<Double> doubles = Arrays.asList(1.5, 2.5, 3.5);17    List<Long> longs = Arrays.asList(10L, 20L, 30L);18    19    System.out.println("  Sum ints: " + sum(ints[1, 2, 3, 4, 5]));20    System.out.println("  Sum doubles: " + sum(doubles));
    outputUpper bounded wildcard:
    Upper bounded wildcard:
  2. total ← 0.0

    pass 1 of 7
    3public class UpperBound {4    public static double sum(List<? extends Number> numbers[1, 2, 3, 4, 5]) {5        double total→ 0.0 = 0;6        for (Number num : numbers) {  // Can read as Number
    All 7 passes — pass 1 is the card above
    passnumberstotal
    1[1, 2, 3, 4, 5]0.0
    2[1, 2, 3, 4, 5]0.0
    3[1.5, 2.5, 3.5]0.0
    4[1.5, 2.5, 3.5]0.0
    5[10, 20, 30]0.0
    6[10, 20, 30]0.0
    7[1, 2, 3, 4, 5]0.0
  3. total ← 1.0

    pass 1 of 27
    5double total = 0;6for (Number num1 : numbers[1, 2, 3, 4, 5]) {  // Can read as Number7    total→ 1.0 += num.doubleValue();8}
    27 passes — pass 1 is the card above
    passnumnumberstotal
    11[1, 2, 3, 4, 5]0.0 1.0
    22[1, 2, 3, 4, 5]1.0 3.0
    33[1, 2, 3, 4, 5]3.0 6.0
    44[1, 2, 3, 4, 5]6.0 10.0
    55[1, 2, 3, 4, 5]10.0 15.0
    61[1, 2, 3, 4, 5]0.0 1.0
    72[1, 2, 3, 4, 5]1.0 3.0
    83[1, 2, 3, 4, 5]3.0 6.0
    94[1, 2, 3, 4, 5]6.0 10.0
    ⋯ 16 more passes ⋯
    264[1, 2, 3, 4, 5]6.0 10.0
    275[1, 2, 3, 4, 5]10.0 15.0
  4. return total;

    8    }9    return total15.0;10}
  5. System.out.println(" Sum ints: " + sum(ints));

    19System.out.println("  Sum ints: " + sum(ints[1, 2, 3, 4, 5]));20System.out.println("  Sum doubles: " + sum(doubles));
    output  Sum ints: 15.0
  6. return total;

    8    }9    return total15.0;10}
  7. System.out.println(" Sum ints: " + sum(ints));

    19System.out.println("  Sum ints: " + sum(ints[1, 2, 3, 4, 5]));20System.out.println("  Sum doubles: " + sum(doubles[1.5, 2.5, 3.5]));21System.out.println("  Sum longs: " + sum(longs));
    output  Sum ints: 15.0
  8. return total;

    8    }9    return total7.5;10}
  9. System.out.println(" Sum doubles: " + sum(doubles));

    19System.out.println("  Sum ints: " + sum(ints));20System.out.println("  Sum doubles: " + sum(doubles[1.5, 2.5, 3.5]));21System.out.println("  Sum longs: " + sum(longs));
    output  Sum doubles: 7.5
  10. return total;

    8    }9    return total7.5;10}
  11. System.out.println(" Sum doubles: " + sum(doubles));

    19System.out.println("  Sum ints: " + sum(ints));20System.out.println("  Sum doubles: " + sum(doubles[1.5, 2.5, 3.5]));21System.out.println("  Sum longs: " + sum(longs[10, 20, 30]));
    output  Sum doubles: 7.5
  12. return total;

    8    }9    return total60.0;10}
  13. System.out.println(" Sum longs: " + sum(longs));

    20System.out.println("  Sum doubles: " + sum(doubles));21System.out.println("  Sum longs: " + sum(longs[10, 20, 30]));
    output  Sum longs: 60.0
  14. return total;

    8    }9    return total60.0;10}
  15. System.out.println(" Sum longs: " + sum(longs));

    20System.out.println("  Sum doubles: " + sum(doubles));21System.out.println("  Sum longs: " + sum(longs[10, 20, 30]));2223// <? extends T> means "unknown type that extends T"24// Can read elements as T25// Cannot add elements (except null) - don't know exact type26// PECS: Producer Extends - use when reading/producing2728System.out.println("\nFind max:");
    output  Sum longs: 60.0
    
    Find max:
    
    Find max:
  16. max ← 1

    pass 1 of 5
    30class Finder {31    public static <T extends Comparable<T>> T max(32            List<? extends T> list[1, 2, 3, 4, 5]) {33        if (list.isEmpty()) {34            return null;35        }36        37        T max→ 1 = list.get(0);38        for (T item : list) {
    All 5 passes — pass 1 is the card above
    passlistmax
    1[1, 2, 3, 4, 5]1
    2[1.5, 2.5, 3.5]1.5
    3[1.5, 2.5, 3.5]1.5
    4[apple, zebra, banana]apple
    5[apple, zebra, banana]apple
  17. for (T item : list)

    pass 1 of 17
    37T max = list.get(0);38for (T item1 : list[1, 2, 3, 4, 5]) {39    if (item.compareTo(max) > 0) {
    17 passes — pass 1 is the card above
    passitemlist
    11[1, 2, 3, 4, 5]
    22[1, 2, 3, 4, 5]
    33[1, 2, 3, 4, 5]
    44[1, 2, 3, 4, 5]
    55[1, 2, 3, 4, 5]
    61.5[1.5, 2.5, 3.5]
    72.5[1.5, 2.5, 3.5]
    83.5[1.5, 2.5, 3.5]
    91.5[1.5, 2.5, 3.5]
    ⋯ 6 more passes ⋯
    16zebra[apple, zebra, banana]
    17banana[apple, zebra, banana]
  18. max ← 2

    pass 1 of 10
    38for (T item : list) {39    if (item.compareTo(max1) > 0) {40        max→ 2 = item2;41    }
    All 10 passes — pass 1 is the card above
    passitemmax
    121 2
    232 3
    343 4
    454 5
    52.51.5 2.5
    63.52.5 3.5
    72.51.5 2.5
    83.52.5 3.5
    9zebraapple zebra
    10zebraapple zebra
  19. return max;

    42    }43    return max5;44}
  20. System.out.println(" Max double: " + Finder.max(doubles));

    47System.out.println("  Max int: " + Finder.max(ints));48System.out.println("  Max double: " + Finder.max(doubles[1.5, 2.5, 3.5]));
  21. return max;

    42    }43    return max3.5;44}
  22. System.out.println(" Max double: " + Finder.max(doubles));

    47System.out.println("  Max int: " + Finder.max(ints));48System.out.println("  Max double: " + Finder.max(doubles[1.5, 2.5, 3.5]));
    output  Max double: 3.5
  23. return max;

    42    }43    return max3.5;44}
  24. System.out.println(" Max double: " + Finder.max(doubles));

    47System.out.println("  Max int: " + Finder.max(ints));48System.out.println("  Max double: " + Finder.max(doubles[1.5, 2.5, 3.5]));4950List<String> words = Arrays.asList("apple", "zebra", "banana");51System.out.println("  Max string: " + Finder.max(words[apple, zebra, banana]));
    output  Max double: 3.5
  25. return max;

    42    }43    return maxzebra;44}
  26. System.out.println(" Max string: " + Finder.max(words));

    50List<String> words = Arrays.asList("apple", "zebra", "banana");51System.out.println("  Max string: " + Finder.max(words[apple, zebra, banana]));
    output  Max string: zebra
  27. return max;

    42    }43    return maxzebra;44}
  28. System.out.println(" Max string: " + Finder.max(words));

    50List<String> words = Arrays.asList("apple", "zebra", "banana");51System.out.println("  Max string: " + Finder.max(words[apple, zebra, banana]));5253System.out.println("\nCopy numbers:");
    output  Max string: zebra
    
    Copy numbers:
    
    Copy numbers:
  29. public static void copyNumbers( List<? extends Num…

    55class Copier {56    public static void copyNumbers(57            List<? extends Number> source[1, 2, 3, 4, 5],58            List<Number> dest[]) {59        dest.clear();60        for (Number num : source) {  // Read as Number
  30. for (Number num : source)

    pass 1 of 5
    59dest.clear();60for (Number num1 : source[1, 2, 3, 4, 5]) {  // Read as Number61    dest.add(num1);62}
    All 5 passes — pass 1 is the card above
    passnum
    11
    22
    33
    44
    55
  31. System.out.println(" Copied: " + result);

    67Copier.copyNumbers(ints, result);68System.out.println("  Copied: " + result[1, 2, 3, 4, 5]);6970System.out.println("\nAverage:");
    output  Copied: [1, 2, 3, 4, 5]
      Copied: [1, 2, 3, 4, 5]
    
    Average:
    
    Average:
  32. public static double average(List<? extends Number> numbers)

    72class Stats {73    public static double average(List<? extends Number> numbers[1, 2, 3, 4, 5]) {74        if (numbers.isEmpty()) {75            return 0;76        }77        return sum(numbers[1, 2, 3, 4, 5]) / numbers.size();78    }
  33. return total;

    8    }9    return total15.0;10}
  34. System.out.println(" Min: " + Stats.min(doubles));

    98System.out.println("  Average: " + Stats.average(ints));99System.out.println("  Min: " + Stats.min(doubles[1.5, 2.5, 3.5]));
  35. minVal ← 1.5, min ← 1.5

    pass 1 of 2
    80public static Number min(List<? extends Number> numbers[1.5, 2.5, 3.5]) {81    if (numbers.isEmpty()) {82        return null;83    }84    85    double minVal→ 1.5 = numbers.get(0).doubleValue();86    Number min→ 1.5 = numbers.get(0);
  36. for (Number num : numbers)

    pass 1 of 6
    88for (Number num1.5 : numbers[1.5, 2.5, 3.5]) {89    if (num.doubleValue() < minVal) {
    All 6 passes — pass 1 is the card above
    passnum
    11.5
    22.5
    33.5
    41.5
    52.5
    63.5
  37. return min;

    93    }94    return min1.5;95}
  38. System.out.println(" Min: " + Stats.min(doubles));

    98System.out.println("  Average: " + Stats.average(ints));99System.out.println("  Min: " + Stats.min(doubles[1.5, 2.5, 3.5]));
    output  Min: 1.5
  39. minVal ← 1.5, min ← 1.5

    pass 2 of 2
    80public static Number min(List<? extends Number> numbers[1.5, 2.5, 3.5]) {81    if (numbers.isEmpty()) {82        return null;83    }84    85    double minVal→ 1.5 = numbers.get(0).doubleValue();86    Number min→ 1.5 = numbers.get(0);
  40. return min;

    93    }94    return min1.5;95}
  41. System.out.println(" Min: " + Stats.min(doubles));

    98System.out.println("  Average: " + Stats.average(ints));99System.out.println("  Min: " + Stats.min(doubles[1.5, 2.5, 3.5]));100101System.out.println("\nPrint comparable:");
    output  Min: 1.5
    
    Print comparable:
    
    Print comparable:
  42. copy ← [5, 1, 9, 3, 7]

    pass 1 of 2
    103class Printer {104    public static <T extends Comparable<T>> void printSorted(105            List<? extends T> list[5, 1, 9, 3, 7]) {106        List<T> copy→ [5, 1, 9, 3, 7] = new ArrayList<>(list);107        Collections.sort(copy→ [1, 3, 5, 7, 9]);108        System.out.print("  Sorted: ");109        for (T item : copy) {
    output  Sorted: 
  43. for (T item : copy)

    pass 1 of 9
    108System.out.print("  Sorted: ");109for (T item1 : copy[1, 3, 5, 7, 9]) {110    System.out.print(item1 + " ");111}
    output1 
    All 9 passes — pass 1 is the card above
    passitemcopy
    11[1, 3, 5, 7, 9]
    23[1, 3, 5, 7, 9]
    35[1, 3, 5, 7, 9]
    47[1, 3, 5, 7, 9]
    59[1, 3, 5, 7, 9]
    6ant[ant, bee, cat, dog]
    7bee[ant, bee, cat, dog]
    8cat[ant, bee, cat, dog]
    9dog[ant, bee, cat, dog]
  44. System.out.println();

    111    }112    System.out.println();113}
  45. Printer.printSorted(Arrays.asList("dog", "cat", "ant", "bee"));

    116Printer.printSorted(Arrays.asList(5, 1, 9, 3, 7));117Printer.printSorted(Arrays.asList("dog", "cat", "ant", "bee"));
  46. copy ← [dog, cat, ant, bee]

    pass 2 of 2
    103class Printer {104    public static <T extends Comparable<T>> void printSorted(105            List<? extends T> list[dog, cat, ant, bee]) {106        List<T> copy→ [dog, cat, ant, bee] = new ArrayList<>(list);107        Collections.sort(copy→ [ant, bee, cat, dog]);108        System.out.print("  Sorted: ");109        for (T item : copy) {
    output  Sorted: 
  47. System.out.println();

    111    }112    System.out.println();113}
  48. numList ← []

    116    Printer.printSorted(Arrays.asList(5, 1, 9, 3, 7));117    Printer.printSorted(Arrays.asList("dog", "cat", "ant", "bee"));118    119    System.out.println("\nLimitations:");120    121    List<? extends Number> numList→ [] = new ArrayList<Integer>();122    // numList.add(1);        // Compile error123    // numList.add(1.5);      // Compile error124    // numList.add(new Integer(1));  // Compile error125    126    System.out.println("  Cannot add to List<? extends Number>");127    System.out.println("  Reason: Don't know if it's Integer, Double, etc.");128}
    output
    Limitations:
      Cannot add to List<? extends Number>
      Reason: Don't know if it's Integer, Double, etc.

List<? extends Number> - accepts List, List, etc.

upper bounded wildcard `<? extends T>` - producer. Read as T, can't add (except null).

Lower bounded wildcard

Accept type or supertypes.

fillCount
LowerBound.java
Replay: real traced execution (multi-file project)
import java.util.*;

public class LowerBound {
    public static void addIntegers(List<? super Integer> list) {
        list.add(1);      // Can add Integer
        list.add(2);
        list.add(3);
        System.out.println("  Added integers: " + list);
    }

    public static void main(String[] args) {
        System.out.println("Lower bounded wildcard:\n");

        List<Integer> intList = new ArrayList<>();
        List<Number> numList = new ArrayList<>();
        List<Object> objList = new ArrayList<>();

        addIntegers(intList);
        addIntegers(numList);
        addIntegers(objList);

        // <? super T> means "unknown type that is T or superclass"
        // Can add T elements
        // Can read as Object only (don't know exact type)
        // PECS: Consumer Super - use when writing/consuming

        System.out.println("\nAdd all:");

        class Adder {
            public static <T> void addAll(
                    List<? super T> dest,
                    List<? extends T> src) {
                for (T item : src) {
                    dest.add(item);  // Can add T to super T
                }
            }
        }

        List<Number> numbers = new ArrayList<>();
        List<Integer> ints = Arrays.asList(10, 20, 30);
        List<Double> doubles = Arrays.asList(1.5, 2.5);

        Adder.addAll(numbers, ints);
        Adder.addAll(numbers, doubles);

        System.out.println("  Combined: " + numbers);

        System.out.println("\nFill list:");

        class Filler {
            public static <T> void fill(List<? super T> list, T value, int count) {
                for (int i = 0; i < count; i++) {
                    list.add(value);
                }
            }
        }

        List<Object> objects = new ArrayList<>();
        int fillCount = 3;
        Filler.fill(objects, "hello", fillCount);
        Filler.fill(objects, 42, 2);

        System.out.println("  Filled: " + objects);

        System.out.println("\nCopy method:");

        class Copier {
            public static <T> void copy(
                    List<? super T> dest,
                    List<? extends T> src) {
                dest.clear();
                for (T item : src) {
                    dest.add(item);
                }
            }
        }

        List<String> source = Arrays.asList("a", "b", "c");
        List<Object> destination = new ArrayList<>();

        Copier.copy(destination, source);
        System.out.println("  Copied: " + destination);

        System.out.println("\nAppend:");

        class Appender {
            public static void appendIntegers(List<? super Integer> list) {
                for (int i = 1; i <= 5; i++) {
                    list.add(i);
                }
            }
        }

        List<Number> nums = new ArrayList<>();
        Appender.appendIntegers(nums);
        System.out.println("  Numbers: " + nums);

        List<Object> objs = new ArrayList<>();
        Appender.appendIntegers(objs);
        System.out.println("  Objects: " + objs);

        System.out.println("\nReading limitations:");

        List<? super Integer> superList = new ArrayList<Number>();
        superList.add(10);
        superList.add(20);

        // Can only read as Object
        Object first = superList.get(0);  // Only Object
        // Integer val = superList.get(0);  // Compile error

        System.out.println("  First (as Object): " + first);
        System.out.println("  Can only read as Object from List<? super Integer>");

        System.out.println("\nPECS example:");

        class PecsDemo {
            // Producer Extends - reading from source
            // Consumer Super - writing to destination
            public static <T> void transfer(
                    List<? super T> dest,      // Consumer - can add T
                    List<? extends T> src) {   // Producer - can read T
                for (T item : src) {
                    dest.add(item);
                }
            }
        }

        List<Integer> intSource = Arrays.asList(1, 2, 3);
        List<Number> numDest = new ArrayList<>();

        PecsDemo.transfer(numDest, intSource);
        System.out.println("  Transferred: " + numDest);
    }
}
import java.util.*;

public class LowerBound {
    public static void addIntegers(List<? super Integer> list) {
        list.add(1);      // Can add Integer
        list.add(2);
        list.add(3);
        System.out.println("  Added integers: " + list);
    }

    public static void main(String[] args) {
        System.out.println("Lower bounded wildcard:\n");

        List<Integer> intList = new ArrayList<>();
        List<Number> numList = new ArrayList<>();
        List<Object> objList = new ArrayList<>();

        addIntegers(intList);
        addIntegers(numList);
        addIntegers(objList);

        // <? super T> means "unknown type that is T or superclass"
        // Can add T elements
        // Can read as Object only (don't know exact type)
        // PECS: Consumer Super - use when writing/consuming

        System.out.println("\nAdd all:");

        class Adder {
            public static <T> void addAll(
                    List<? super T> dest,
                    List<? extends T> src) {
                for (T item : src) {
                    dest.add(item);  // Can add T to super T
                }
            }
        }

        List<Number> numbers = new ArrayList<>();
        List<Integer> ints = Arrays.asList(10, 20, 30);
        List<Double> doubles = Arrays.asList(1.5, 2.5);

        Adder.addAll(numbers, ints);
        Adder.addAll(numbers, doubles);

        System.out.println("  Combined: " + numbers);

        System.out.println("\nFill list:");

        class Filler {
            public static <T> void fill(List<? super T> list, T value, int count) {
                for (int i = 0; i < count; i++) {
                    list.add(value);
                }
            }
        }

        List<Object> objects = new ArrayList<>();
        int fillCount = 1;
        Filler.fill(objects, "hello", fillCount);
        Filler.fill(objects, 42, 2);

        System.out.println("  Filled: " + objects);

        System.out.println("\nCopy method:");

        class Copier {
            public static <T> void copy(
                    List<? super T> dest,
                    List<? extends T> src) {
                dest.clear();
                for (T item : src) {
                    dest.add(item);
                }
            }
        }

        List<String> source = Arrays.asList("a", "b", "c");
        List<Object> destination = new ArrayList<>();

        Copier.copy(destination, source);
        System.out.println("  Copied: " + destination);

        System.out.println("\nAppend:");

        class Appender {
            public static void appendIntegers(List<? super Integer> list) {
                for (int i = 1; i <= 5; i++) {
                    list.add(i);
                }
            }
        }

        List<Number> nums = new ArrayList<>();
        Appender.appendIntegers(nums);
        System.out.println("  Numbers: " + nums);

        List<Object> objs = new ArrayList<>();
        Appender.appendIntegers(objs);
        System.out.println("  Objects: " + objs);

        System.out.println("\nReading limitations:");

        List<? super Integer> superList = new ArrayList<Number>();
        superList.add(10);
        superList.add(20);

        // Can only read as Object
        Object first = superList.get(0);  // Only Object
        // Integer val = superList.get(0);  // Compile error

        System.out.println("  First (as Object): " + first);
        System.out.println("  Can only read as Object from List<? super Integer>");

        System.out.println("\nPECS example:");

        class PecsDemo {
            // Producer Extends - reading from source
            // Consumer Super - writing to destination
            public static <T> void transfer(
                    List<? super T> dest,      // Consumer - can add T
                    List<? extends T> src) {   // Producer - can read T
                for (T item : src) {
                    dest.add(item);
                }
            }
        }

        List<Integer> intSource = Arrays.asList(1, 2, 3);
        List<Number> numDest = new ArrayList<>();

        PecsDemo.transfer(numDest, intSource);
        System.out.println("  Transferred: " + numDest);
    }
}
import java.util.*;

public class LowerBound {
    public static void addIntegers(List<? super Integer> list) {
        list.add(1);      // Can add Integer
        list.add(2);
        list.add(3);
        System.out.println("  Added integers: " + list);
    }

    public static void main(String[] args) {
        System.out.println("Lower bounded wildcard:\n");

        List<Integer> intList = new ArrayList<>();
        List<Number> numList = new ArrayList<>();
        List<Object> objList = new ArrayList<>();

        addIntegers(intList);
        addIntegers(numList);
        addIntegers(objList);

        // <? super T> means "unknown type that is T or superclass"
        // Can add T elements
        // Can read as Object only (don't know exact type)
        // PECS: Consumer Super - use when writing/consuming

        System.out.println("\nAdd all:");

        class Adder {
            public static <T> void addAll(
                    List<? super T> dest,
                    List<? extends T> src) {
                for (T item : src) {
                    dest.add(item);  // Can add T to super T
                }
            }
        }

        List<Number> numbers = new ArrayList<>();
        List<Integer> ints = Arrays.asList(10, 20, 30);
        List<Double> doubles = Arrays.asList(1.5, 2.5);

        Adder.addAll(numbers, ints);
        Adder.addAll(numbers, doubles);

        System.out.println("  Combined: " + numbers);

        System.out.println("\nFill list:");

        class Filler {
            public static <T> void fill(List<? super T> list, T value, int count) {
                for (int i = 0; i < count; i++) {
                    list.add(value);
                }
            }
        }

        List<Object> objects = new ArrayList<>();
        int fillCount = 5;
        Filler.fill(objects, "hello", fillCount);
        Filler.fill(objects, 42, 2);

        System.out.println("  Filled: " + objects);

        System.out.println("\nCopy method:");

        class Copier {
            public static <T> void copy(
                    List<? super T> dest,
                    List<? extends T> src) {
                dest.clear();
                for (T item : src) {
                    dest.add(item);
                }
            }
        }

        List<String> source = Arrays.asList("a", "b", "c");
        List<Object> destination = new ArrayList<>();

        Copier.copy(destination, source);
        System.out.println("  Copied: " + destination);

        System.out.println("\nAppend:");

        class Appender {
            public static void appendIntegers(List<? super Integer> list) {
                for (int i = 1; i <= 5; i++) {
                    list.add(i);
                }
            }
        }

        List<Number> nums = new ArrayList<>();
        Appender.appendIntegers(nums);
        System.out.println("  Numbers: " + nums);

        List<Object> objs = new ArrayList<>();
        Appender.appendIntegers(objs);
        System.out.println("  Objects: " + objs);

        System.out.println("\nReading limitations:");

        List<? super Integer> superList = new ArrayList<Number>();
        superList.add(10);
        superList.add(20);

        // Can only read as Object
        Object first = superList.get(0);  // Only Object
        // Integer val = superList.get(0);  // Compile error

        System.out.println("  First (as Object): " + first);
        System.out.println("  Can only read as Object from List<? super Integer>");

        System.out.println("\nPECS example:");

        class PecsDemo {
            // Producer Extends - reading from source
            // Consumer Super - writing to destination
            public static <T> void transfer(
                    List<? super T> dest,      // Consumer - can add T
                    List<? extends T> src) {   // Producer - can read T
                for (T item : src) {
                    dest.add(item);
                }
            }
        }

        List<Integer> intSource = Arrays.asList(1, 2, 3);
        List<Number> numDest = new ArrayList<>();

        PecsDemo.transfer(numDest, intSource);
        System.out.println("  Transferred: " + numDest);
    }
}
  1. public static void main(String[] args)

    11public static void main(String[] args) {12    System.out.println("Lower bounded wildcard:\n");
    outputLower bounded wildcard:
    Lower bounded wildcard:
  2. public static void addIntegers(List<? super Integer> list)

    pass 1 of 3
    3public class LowerBound {4    public static void addIntegers(List<? super Integer> list[]) {5        list.add(1);      // Can add Integer6        list.add(2);7        list.add(3);8        System.out.println("  Added integers: " + list[1, 2, 3]);9    }
    output  Added integers: [1, 2, 3]
  3. System.out.println(" Add all:");

    27System.out.println("\nAdd all:");
    output
    Add all:
    
    Add all:
  4. public static <T> void addAll( List<? super T> des…

    pass 1 of 2
    29class Adder {30    public static <T> void addAll(31            List<? super T> dest[],32            List<? extends T> src[10, 20, 30]) {33        for (T item : src) {
  5. for (T item : src)

    pass 1 of 5
    32    List<? extends T> src) {33for (T item10 : src[10, 20, 30]) {34    dest.add(item10);  // Can add T to super T35}
    All 5 passes — pass 1 is the card above
    passitemsrcdest
    110[10, 20, 30]
    220[10, 20, 30]
    330[10, 20, 30][10, 20, 30]
    41.5[1.5, 2.5]
    52.5[1.5, 2.5]
  6. public static <T> void addAll( List<? super T> des…

    pass 2 of 2
    29class Adder {30    public static <T> void addAll(31            List<? super T> dest[10, 20, 30],32            List<? extends T> src[1.5, 2.5]) {33        for (T item : src) {
  7. System.out.println(" Combined: " + numbers);

    46System.out.println("  Combined: " + numbers[10, 20, 30, 1.5, 2.5]);4748System.out.println("\nFill list:");
    output  Combined: [10, 20, 30, 1.5, 2.5]
      Combined: [10, 20, 30, 1.5, 2.5]
    
    Fill list:
    
    Fill list:
  8. public static <T> void fill(List<? super T> list, T value, int count)

    pass 1 of 2
    50class Filler {51    public static <T> void fill(List<? super T> list[], T valuehello, int count3) {52        for (int i = 0; i < count; i++) {
  9. for (int i = 0; i < count; i++)

    pass 1 of 5
    51public static <T> void fill(List<? super T> list, T value, int count) {52    for (int i0 = 0; i < count3; i++) {53        list.add(valuehello);54    }
    All 5 passes — pass 1 is the card above
    passicountvaluelist
    103hello
    213hello
    323hello[hello, hello, hello]
    40242
    51242
  10. public static <T> void fill(List<? super T> list, T value, int count)

    pass 2 of 2
    50class Filler {51    public static <T> void fill(List<? super T> list[hello, hello, hello], T value42, int count2) {52        for (int i = 0; i < count; i++) {
  11. System.out.println(" Filled: " + objects);

    63System.out.println("  Filled: " + objects[hello, hello, hello, 42, 42]);6465System.out.println("\nCopy method:");
    output  Filled: [hello, hello, hello, 42, 42]
      Filled: [hello, hello, hello, 42, 42]
    
    Copy method:
    
    Copy method:
  12. public static <T> void copy( List<? super T> dest,…

    67class Copier {68    public static <T> void copy(69            List<? super T> dest[],70            List<? extends T> src[a, b, c]) {71        dest.clear();72        for (T item : src) {
  13. for (T item : src)

    pass 1 of 3
    71dest.clear();72for (T itema : src[a, b, c]) {73    dest.add(itema);74}
    All 3 passes — pass 1 is the card above
    passitem
    1a
    2b
    3c
  14. System.out.println(" Copied: " + destination);

    81Copier.copy(destination, source);82System.out.println("  Copied: " + destination[a, b, c]);8384System.out.println("\nAppend:");
    output  Copied: [a, b, c]
      Copied: [a, b, c]
    
    Append:
    
    Append:
  15. public static void appendIntegers(List<? super Integer> list)

    pass 1 of 2
    86class Appender {87    public static void appendIntegers(List<? super Integer> list[]) {88        for (int i = 1; i <= 5; i++) {
  16. for (int i = 1; i <= 5; i++)

    pass 1 of 10
    87public static void appendIntegers(List<? super Integer> list) {88    for (int i1 = 1; i <= 5; i++) {89        list.add(i1);90    }
    All 10 passes — pass 1 is the card above
    passi
    11
    22
    33
    44
    55
    61
    72
    83
    94
    105
  17. System.out.println(" Numbers: " + nums);

    95Appender.appendIntegers(nums);96System.out.println("  Numbers: " + nums[1, 2, 3, 4, 5]);
    output  Numbers: [1, 2, 3, 4, 5]
      Numbers: [1, 2, 3, 4, 5]
  18. public static void appendIntegers(List<? super Integer> list)

    pass 2 of 2
    86class Appender {87    public static void appendIntegers(List<? super Integer> list[]) {88        for (int i = 1; i <= 5; i++) {
  19. numDest ← []

    99Appender.appendIntegers(objs);100System.out.println("  Objects: " + objs[1, 2, 3, 4, 5]);101102System.out.println("\nReading limitations:");103104List<? super Integer> superList = new ArrayList<Number>();105superList.add(10);106superList.add(20);107108// Can only read as Object109Object first = superList.get(0);  // Only Object110// Integer val = superList.get(0);  // Compile error111112System.out.println("  First (as Object): " + first10);113System.out.println("  Can only read as Object from List<? super Integer>");114115System.out.println("\nPECS example:");116117class PecsDemo {118    // Producer Extends - reading from source119    // Consumer Super - writing to destination120    public static <T> void transfer(121            List<? super T> dest,      // Consumer - can add T122            List<? extends T> src) {   // Producer - can read T123        for (T item : src) {124            dest.add(item);125        }126    }127}128129List<Integer> intSource = Arrays.asList(1, 2, 3);130List<Number> numDest→ [] = new ArrayList<>();131132PecsDemo.transfer(numDest[], intSource[1, 2, 3]);133System.out.println("  Transferred: " + numDest);
    output  Objects: [1, 2, 3, 4, 5]
      Objects: [1, 2, 3, 4, 5]
    
    Reading limitations:
    
    Reading limitations:
      First (as Object): 10
      First (as Object): 10
      Can only read as Object from List<? super Integer>
      Can only read as Object from List<? super Integer>
    
    PECS example:
    
    PECS example:
  20. public static <T> void transfer( List<? super T> d…

    119// Consumer Super - writing to destination120public static <T> void transfer(121        List<? super T> dest[],      // Consumer - can add T122        List<? extends T> src[1, 2, 3]) {   // Producer - can read T123    for (T item : src) {
  21. for (T item : src)

    pass 1 of 3
    122    List<? extends T> src) {   // Producer - can read T123for (T item1 : src[1, 2, 3]) {124    dest.add(item1);125}
    All 3 passes — pass 1 is the card above
    passitem
    11
    22
    33
  22. numDest ← [1, 2, 3]

    132    PecsDemo.transfer(numDest→ [1, 2, 3], intSource[1, 2, 3]);133    System.out.println("  Transferred: " + numDest[1, 2, 3]);134}
    output  Transferred: [1, 2, 3]
  1. public static void main(String[] args)

    11public static void main(String[] args) {12    System.out.println("Lower bounded wildcard:\n");
    outputLower bounded wildcard:
    Lower bounded wildcard:
  2. public static void addIntegers(List<? super Integer> list)

    pass 1 of 3
    3public class LowerBound {4    public static void addIntegers(List<? super Integer> list[]) {5        list.add(1);      // Can add Integer6        list.add(2);7        list.add(3);8        System.out.println("  Added integers: " + list[1, 2, 3]);9    }
    output  Added integers: [1, 2, 3]
  3. System.out.println(" Add all:");

    27System.out.println("\nAdd all:");
    output
    Add all:
    
    Add all:
  4. public static <T> void addAll( List<? super T> des…

    pass 1 of 2
    29class Adder {30    public static <T> void addAll(31            List<? super T> dest[],32            List<? extends T> src[10, 20, 30]) {33        for (T item : src) {
  5. for (T item : src)

    pass 1 of 5
    32    List<? extends T> src) {33for (T item10 : src[10, 20, 30]) {34    dest.add(item10);  // Can add T to super T35}
    All 5 passes — pass 1 is the card above
    passitemsrcdest
    110[10, 20, 30]
    220[10, 20, 30]
    330[10, 20, 30][10, 20, 30]
    41.5[1.5, 2.5]
    52.5[1.5, 2.5]
  6. public static <T> void addAll( List<? super T> des…

    pass 2 of 2
    29class Adder {30    public static <T> void addAll(31            List<? super T> dest[10, 20, 30],32            List<? extends T> src[1.5, 2.5]) {33        for (T item : src) {
  7. System.out.println(" Combined: " + numbers);

    46System.out.println("  Combined: " + numbers[10, 20, 30, 1.5, 2.5]);4748System.out.println("\nFill list:");
    output  Combined: [10, 20, 30, 1.5, 2.5]
      Combined: [10, 20, 30, 1.5, 2.5]
    
    Fill list:
    
    Fill list:
  8. public static <T> void fill(List<? super T> list, T value, int count)

    pass 1 of 2
    50class Filler {51    public static <T> void fill(List<? super T> list[], T valuehello, int count1) {52        for (int i = 0; i < count; i++) {
  9. for (int i = 0; i < count; i++)

    pass 1 of 3
    51public static <T> void fill(List<? super T> list, T value, int count) {52    for (int i0 = 0; i < count1; i++) {53        list.add(valuehello);54    }
    All 3 passes — pass 1 is the card above
    passicountvaluelist
    101hello[hello]
    20242
    31242
  10. public static <T> void fill(List<? super T> list, T value, int count)

    pass 2 of 2
    50class Filler {51    public static <T> void fill(List<? super T> list[hello], T value42, int count2) {52        for (int i = 0; i < count; i++) {
  11. System.out.println(" Filled: " + objects);

    63System.out.println("  Filled: " + objects[hello, 42, 42]);6465System.out.println("\nCopy method:");
    output  Filled: [hello, 42, 42]
      Filled: [hello, 42, 42]
    
    Copy method:
    
    Copy method:
  12. public static <T> void copy( List<? super T> dest,…

    67class Copier {68    public static <T> void copy(69            List<? super T> dest[],70            List<? extends T> src[a, b, c]) {71        dest.clear();72        for (T item : src) {
  13. for (T item : src)

    pass 1 of 3
    71dest.clear();72for (T itema : src[a, b, c]) {73    dest.add(itema);74}
    All 3 passes — pass 1 is the card above
    passitem
    1a
    2b
    3c
  14. System.out.println(" Copied: " + destination);

    81Copier.copy(destination, source);82System.out.println("  Copied: " + destination[a, b, c]);8384System.out.println("\nAppend:");
    output  Copied: [a, b, c]
      Copied: [a, b, c]
    
    Append:
    
    Append:
  15. public static void appendIntegers(List<? super Integer> list)

    pass 1 of 2
    86class Appender {87    public static void appendIntegers(List<? super Integer> list[]) {88        for (int i = 1; i <= 5; i++) {
  16. for (int i = 1; i <= 5; i++)

    pass 1 of 10
    87public static void appendIntegers(List<? super Integer> list) {88    for (int i1 = 1; i <= 5; i++) {89        list.add(i1);90    }
    All 10 passes — pass 1 is the card above
    passi
    11
    22
    33
    44
    55
    61
    72
    83
    94
    105
  17. System.out.println(" Numbers: " + nums);

    95Appender.appendIntegers(nums);96System.out.println("  Numbers: " + nums[1, 2, 3, 4, 5]);
    output  Numbers: [1, 2, 3, 4, 5]
      Numbers: [1, 2, 3, 4, 5]
  18. public static void appendIntegers(List<? super Integer> list)

    pass 2 of 2
    86class Appender {87    public static void appendIntegers(List<? super Integer> list[]) {88        for (int i = 1; i <= 5; i++) {
  19. numDest ← []

    99Appender.appendIntegers(objs);100System.out.println("  Objects: " + objs[1, 2, 3, 4, 5]);101102System.out.println("\nReading limitations:");103104List<? super Integer> superList = new ArrayList<Number>();105superList.add(10);106superList.add(20);107108// Can only read as Object109Object first = superList.get(0);  // Only Object110// Integer val = superList.get(0);  // Compile error111112System.out.println("  First (as Object): " + first10);113System.out.println("  Can only read as Object from List<? super Integer>");114115System.out.println("\nPECS example:");116117class PecsDemo {118    // Producer Extends - reading from source119    // Consumer Super - writing to destination120    public static <T> void transfer(121            List<? super T> dest,      // Consumer - can add T122            List<? extends T> src) {   // Producer - can read T123        for (T item : src) {124            dest.add(item);125        }126    }127}128129List<Integer> intSource = Arrays.asList(1, 2, 3);130List<Number> numDest→ [] = new ArrayList<>();131132PecsDemo.transfer(numDest[], intSource[1, 2, 3]);133System.out.println("  Transferred: " + numDest);
    output  Objects: [1, 2, 3, 4, 5]
      Objects: [1, 2, 3, 4, 5]
    
    Reading limitations:
    
    Reading limitations:
      First (as Object): 10
      First (as Object): 10
      Can only read as Object from List<? super Integer>
      Can only read as Object from List<? super Integer>
    
    PECS example:
    
    PECS example:
  20. public static <T> void transfer( List<? super T> d…

    119// Consumer Super - writing to destination120public static <T> void transfer(121        List<? super T> dest[],      // Consumer - can add T122        List<? extends T> src[1, 2, 3]) {   // Producer - can read T123    for (T item : src) {
  21. for (T item : src)

    pass 1 of 3
    122    List<? extends T> src) {   // Producer - can read T123for (T item1 : src[1, 2, 3]) {124    dest.add(item1);125}
    All 3 passes — pass 1 is the card above
    passitem
    11
    22
    33
  22. numDest ← [1, 2, 3]

    132    PecsDemo.transfer(numDest→ [1, 2, 3], intSource[1, 2, 3]);133    System.out.println("  Transferred: " + numDest[1, 2, 3]);134}
    output  Transferred: [1, 2, 3]
  1. public static void main(String[] args)

    11public static void main(String[] args) {12    System.out.println("Lower bounded wildcard:\n");
    outputLower bounded wildcard:
    Lower bounded wildcard:
  2. public static void addIntegers(List<? super Integer> list)

    pass 1 of 3
    3public class LowerBound {4    public static void addIntegers(List<? super Integer> list[]) {5        list.add(1);      // Can add Integer6        list.add(2);7        list.add(3);8        System.out.println("  Added integers: " + list[1, 2, 3]);9    }
    output  Added integers: [1, 2, 3]
  3. System.out.println(" Add all:");

    27System.out.println("\nAdd all:");
    output
    Add all:
    
    Add all:
  4. public static <T> void addAll( List<? super T> des…

    pass 1 of 2
    29class Adder {30    public static <T> void addAll(31            List<? super T> dest[],32            List<? extends T> src[10, 20, 30]) {33        for (T item : src) {
  5. for (T item : src)

    pass 1 of 5
    32    List<? extends T> src) {33for (T item10 : src[10, 20, 30]) {34    dest.add(item10);  // Can add T to super T35}
    All 5 passes — pass 1 is the card above
    passitemsrcdest
    110[10, 20, 30]
    220[10, 20, 30]
    330[10, 20, 30][10, 20, 30]
    41.5[1.5, 2.5]
    52.5[1.5, 2.5]
  6. public static <T> void addAll( List<? super T> des…

    pass 2 of 2
    29class Adder {30    public static <T> void addAll(31            List<? super T> dest[10, 20, 30],32            List<? extends T> src[1.5, 2.5]) {33        for (T item : src) {
  7. System.out.println(" Combined: " + numbers);

    46System.out.println("  Combined: " + numbers[10, 20, 30, 1.5, 2.5]);4748System.out.println("\nFill list:");
    output  Combined: [10, 20, 30, 1.5, 2.5]
      Combined: [10, 20, 30, 1.5, 2.5]
    
    Fill list:
    
    Fill list:
  8. public static <T> void fill(List<? super T> list, T value, int count)

    pass 1 of 2
    50class Filler {51    public static <T> void fill(List<? super T> list[], T valuehello, int count5) {52        for (int i = 0; i < count; i++) {
  9. for (int i = 0; i < count; i++)

    pass 1 of 7
    51public static <T> void fill(List<? super T> list, T value, int count) {52    for (int i0 = 0; i < count5; i++) {53        list.add(valuehello);54    }
    All 7 passes — pass 1 is the card above
    passicountvaluelist
    105hello
    215hello
    325hello
    435hello
    545hello[hello, hello, hello, hello, hello]
    60242
    71242
  10. public static <T> void fill(List<? super T> list, T value, int count)

    pass 2 of 2
    50class Filler {51    public static <T> void fill(List<? super T> list[hello, hello, hello, hello, hello], T value42, int count2) {52        for (int i = 0; i < count; i++) {
  11. System.out.println(" Filled: " + objects);

    63System.out.println("  Filled: " + objects[hello, hello, hello, hello, hello, 42, 42]);6465System.out.println("\nCopy method:");
    output  Filled: [hello, hello, hello, hello, hello, 42, 42]
      Filled: [hello, hello, hello, hello, hello, 42, 42]
    
    Copy method:
    
    Copy method:
  12. public static <T> void copy( List<? super T> dest,…

    67class Copier {68    public static <T> void copy(69            List<? super T> dest[],70            List<? extends T> src[a, b, c]) {71        dest.clear();72        for (T item : src) {
  13. for (T item : src)

    pass 1 of 3
    71dest.clear();72for (T itema : src[a, b, c]) {73    dest.add(itema);74}
    All 3 passes — pass 1 is the card above
    passitem
    1a
    2b
    3c
  14. System.out.println(" Copied: " + destination);

    81Copier.copy(destination, source);82System.out.println("  Copied: " + destination[a, b, c]);8384System.out.println("\nAppend:");
    output  Copied: [a, b, c]
      Copied: [a, b, c]
    
    Append:
    
    Append:
  15. public static void appendIntegers(List<? super Integer> list)

    pass 1 of 2
    86class Appender {87    public static void appendIntegers(List<? super Integer> list[]) {88        for (int i = 1; i <= 5; i++) {
  16. for (int i = 1; i <= 5; i++)

    pass 1 of 10
    87public static void appendIntegers(List<? super Integer> list) {88    for (int i1 = 1; i <= 5; i++) {89        list.add(i1);90    }
    All 10 passes — pass 1 is the card above
    passi
    11
    22
    33
    44
    55
    61
    72
    83
    94
    105
  17. System.out.println(" Numbers: " + nums);

    95Appender.appendIntegers(nums);96System.out.println("  Numbers: " + nums[1, 2, 3, 4, 5]);
    output  Numbers: [1, 2, 3, 4, 5]
      Numbers: [1, 2, 3, 4, 5]
  18. public static void appendIntegers(List<? super Integer> list)

    pass 2 of 2
    86class Appender {87    public static void appendIntegers(List<? super Integer> list[]) {88        for (int i = 1; i <= 5; i++) {
  19. numDest ← []

    99Appender.appendIntegers(objs);100System.out.println("  Objects: " + objs[1, 2, 3, 4, 5]);101102System.out.println("\nReading limitations:");103104List<? super Integer> superList = new ArrayList<Number>();105superList.add(10);106superList.add(20);107108// Can only read as Object109Object first = superList.get(0);  // Only Object110// Integer val = superList.get(0);  // Compile error111112System.out.println("  First (as Object): " + first10);113System.out.println("  Can only read as Object from List<? super Integer>");114115System.out.println("\nPECS example:");116117class PecsDemo {118    // Producer Extends - reading from source119    // Consumer Super - writing to destination120    public static <T> void transfer(121            List<? super T> dest,      // Consumer - can add T122            List<? extends T> src) {   // Producer - can read T123        for (T item : src) {124            dest.add(item);125        }126    }127}128129List<Integer> intSource = Arrays.asList(1, 2, 3);130List<Number> numDest→ [] = new ArrayList<>();131132PecsDemo.transfer(numDest[], intSource[1, 2, 3]);133System.out.println("  Transferred: " + numDest);
    output  Objects: [1, 2, 3, 4, 5]
      Objects: [1, 2, 3, 4, 5]
    
    Reading limitations:
    
    Reading limitations:
      First (as Object): 10
      First (as Object): 10
      Can only read as Object from List<? super Integer>
      Can only read as Object from List<? super Integer>
    
    PECS example:
    
    PECS example:
  20. public static <T> void transfer( List<? super T> d…

    119// Consumer Super - writing to destination120public static <T> void transfer(121        List<? super T> dest[],      // Consumer - can add T122        List<? extends T> src[1, 2, 3]) {   // Producer - can read T123    for (T item : src) {
  21. for (T item : src)

    pass 1 of 3
    122    List<? extends T> src) {   // Producer - can read T123for (T item1 : src[1, 2, 3]) {124    dest.add(item1);125}
    All 3 passes — pass 1 is the card above
    passitem
    11
    22
    33
  22. numDest ← [1, 2, 3]

    132    PecsDemo.transfer(numDest→ [1, 2, 3], intSource[1, 2, 3]);133    System.out.println("  Transferred: " + numDest[1, 2, 3]);134}
    output  Transferred: [1, 2, 3]

List<? super Integer> - accepts List, List, List.

lower bounded wildcard `<? super T>` - consumer. Can add T, read only as Object.

PECS principle

Producer Extends, Consumer Super.

frequencyTarget
Pecs.java
Replay: real traced execution (multi-file project)
import java.util.*;

public class Pecs {
    static class Stack<E> {
        private List<E> elements = new ArrayList<>();

        public void push(E item) {
            elements.add(item);
        }

        public E pop() {
            if (elements.isEmpty()) {
                return null;
            }
            return elements.remove(elements.size() - 1);
        }

        // Producer - pushes items from src to this stack
        public void pushAll(Iterable<? extends E> src) {
            for (E item : src) {  // Reading from producer
                push(item);
            }
        }

        // Consumer - pops items from this stack to dst
        public void popAll(Collection<? super E> dst) {
            while (!elements.isEmpty()) {
                dst.add(pop());  // Writing to consumer
            }
        }

        public int size() {
            return elements.size();
        }
    }

    public static void main(String[] args) {
        System.out.println("PECS principle:\n");

        Stack<Number> numberStack = new Stack<>();

        // Producer Extends - can push from Integer list
        List<Integer> ints = Arrays.asList(1, 2, 3);
        numberStack.pushAll(ints);

        System.out.println("  Pushed integers, size: " + numberStack.size());

        // Consumer Super - can pop to Object list
        List<Object> objects = new ArrayList<>();
        numberStack.popAll(objects);

        System.out.println("  Popped to objects: " + objects);

        // PECS: Producer Extends, Consumer Super
        // Producer (reading): use <? extends T>
        // Consumer (writing): use <? super T>
        // Maximizes flexibility while maintaining type safety

        System.out.println("\nCollection utilities:");

        class CollectionUtils {
            // Producer - reading from source
            public static <T> void copy(
                    List<? super T> dest,      // Consumer - writing
                    List<? extends T> src) {   // Producer - reading
                dest.clear();
                for (T item : src) {
                    dest.add(item);
                }
            }

            // Producer - reading from multiple sources
            public static <T> void addAll(
                    Collection<? super T> dest,  // Consumer
                    Collection<? extends T>... sources) {  // Producers
                for (Collection<? extends T> src : sources) {
                    for (T item : src) {
                        dest.add(item);
                    }
                }
            }
        }

        List<Integer> intList = Arrays.asList(1, 2, 3);
        List<Double> doubleList = Arrays.asList(1.5, 2.5);
        List<Number> numberList = new ArrayList<>();

        CollectionUtils.addAll(numberList, intList, doubleList);
        System.out.println("  Combined: " + numberList);

        System.out.println("\nFrequency counter:");

        class Counter {
            public static <T> int frequency(
                    Collection<? extends T> collection,  // Producer
                    T target) {
                int count = 0;
                for (T item : collection) {  // Reading
                    if (item != null && item.equals(target)) {
                        count++;
                    }
                }
                return count;
            }
        }

        List<Integer> numbers = Arrays.asList(1, 2, 3, 2, 1, 2);
        int frequencyTarget = 2;
        System.out.println("  Frequency of " + frequencyTarget + ": " +
                         Counter.frequency(numbers, frequencyTarget));

        System.out.println("\nMax with comparator:");

        class MaxFinder {
            public static <T> T max(
                    Collection<? extends T> coll,  // Producer - reading
                    Comparator<? super T> comp) {  // Consumer - comparing
                if (coll.isEmpty()) {
                    return null;
                }

                Iterator<? extends T> it = coll.iterator();
                T max = it.next();

                while (it.hasNext()) {
                    T item = it.next();
                    if (comp.compare(item, max) > 0) {
                        max = item;
                    }
                }
                return max;
            }
        }

        List<String> words = Arrays.asList("apple", "zoo", "banana");
        String maxWord = MaxFinder.max(words, String::compareTo);
        System.out.println("  Max word: " + maxWord);

        System.out.println("\nFilter:");

        interface Predicate<T> {
            boolean test(T item);
        }

        class Filter {
            public static <T> void removeIf(
                    Collection<? extends T> source,   // Producer - reading
                    Collection<? super T> dest,       // Consumer - writing
                    Predicate<? super T> filter) {    // Consumer - testing
                for (T item : source) {
                    if (!filter.test(item)) {
                        dest.add(item);
                    }
                }
            }
        }

        List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
        List<Number> evens = new ArrayList<>();

        Filter.removeIf(nums, evens, n -> n % 2 != 0);  // Keep evens
        System.out.println("  Even numbers: " + evens);

        System.out.println("\nMap transformation:");

        interface Function<T, R> {
            R apply(T item);
        }

        class Mapper {
            public static <T, R> void map(
                    Collection<? extends T> source,  // Producer
                    Collection<? super R> dest,      // Consumer
                    Function<? super T, ? extends R> mapper) {
                for (T item : source) {
                    R result = mapper.apply(item);
                    dest.add(result);
                }
            }
        }

        List<String> strings = Arrays.asList("1", "2", "3");
        List<Object> parsed = new ArrayList<>();

        Mapper.map(strings, parsed, Integer::parseInt);
        System.out.println("  Parsed: " + parsed);
    }
}
import java.util.*;

public class Pecs {
    static class Stack<E> {
        private List<E> elements = new ArrayList<>();

        public void push(E item) {
            elements.add(item);
        }

        public E pop() {
            if (elements.isEmpty()) {
                return null;
            }
            return elements.remove(elements.size() - 1);
        }

        // Producer - pushes items from src to this stack
        public void pushAll(Iterable<? extends E> src) {
            for (E item : src) {  // Reading from producer
                push(item);
            }
        }

        // Consumer - pops items from this stack to dst
        public void popAll(Collection<? super E> dst) {
            while (!elements.isEmpty()) {
                dst.add(pop());  // Writing to consumer
            }
        }

        public int size() {
            return elements.size();
        }
    }

    public static void main(String[] args) {
        System.out.println("PECS principle:\n");

        Stack<Number> numberStack = new Stack<>();

        // Producer Extends - can push from Integer list
        List<Integer> ints = Arrays.asList(1, 2, 3);
        numberStack.pushAll(ints);

        System.out.println("  Pushed integers, size: " + numberStack.size());

        // Consumer Super - can pop to Object list
        List<Object> objects = new ArrayList<>();
        numberStack.popAll(objects);

        System.out.println("  Popped to objects: " + objects);

        // PECS: Producer Extends, Consumer Super
        // Producer (reading): use <? extends T>
        // Consumer (writing): use <? super T>
        // Maximizes flexibility while maintaining type safety

        System.out.println("\nCollection utilities:");

        class CollectionUtils {
            // Producer - reading from source
            public static <T> void copy(
                    List<? super T> dest,      // Consumer - writing
                    List<? extends T> src) {   // Producer - reading
                dest.clear();
                for (T item : src) {
                    dest.add(item);
                }
            }

            // Producer - reading from multiple sources
            public static <T> void addAll(
                    Collection<? super T> dest,  // Consumer
                    Collection<? extends T>... sources) {  // Producers
                for (Collection<? extends T> src : sources) {
                    for (T item : src) {
                        dest.add(item);
                    }
                }
            }
        }

        List<Integer> intList = Arrays.asList(1, 2, 3);
        List<Double> doubleList = Arrays.asList(1.5, 2.5);
        List<Number> numberList = new ArrayList<>();

        CollectionUtils.addAll(numberList, intList, doubleList);
        System.out.println("  Combined: " + numberList);

        System.out.println("\nFrequency counter:");

        class Counter {
            public static <T> int frequency(
                    Collection<? extends T> collection,  // Producer
                    T target) {
                int count = 0;
                for (T item : collection) {  // Reading
                    if (item != null && item.equals(target)) {
                        count++;
                    }
                }
                return count;
            }
        }

        List<Integer> numbers = Arrays.asList(1, 2, 3, 2, 1, 2);
        int frequencyTarget = 1;
        System.out.println("  Frequency of " + frequencyTarget + ": " +
                         Counter.frequency(numbers, frequencyTarget));

        System.out.println("\nMax with comparator:");

        class MaxFinder {
            public static <T> T max(
                    Collection<? extends T> coll,  // Producer - reading
                    Comparator<? super T> comp) {  // Consumer - comparing
                if (coll.isEmpty()) {
                    return null;
                }

                Iterator<? extends T> it = coll.iterator();
                T max = it.next();

                while (it.hasNext()) {
                    T item = it.next();
                    if (comp.compare(item, max) > 0) {
                        max = item;
                    }
                }
                return max;
            }
        }

        List<String> words = Arrays.asList("apple", "zoo", "banana");
        String maxWord = MaxFinder.max(words, String::compareTo);
        System.out.println("  Max word: " + maxWord);

        System.out.println("\nFilter:");

        interface Predicate<T> {
            boolean test(T item);
        }

        class Filter {
            public static <T> void removeIf(
                    Collection<? extends T> source,   // Producer - reading
                    Collection<? super T> dest,       // Consumer - writing
                    Predicate<? super T> filter) {    // Consumer - testing
                for (T item : source) {
                    if (!filter.test(item)) {
                        dest.add(item);
                    }
                }
            }
        }

        List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
        List<Number> evens = new ArrayList<>();

        Filter.removeIf(nums, evens, n -> n % 2 != 0);  // Keep evens
        System.out.println("  Even numbers: " + evens);

        System.out.println("\nMap transformation:");

        interface Function<T, R> {
            R apply(T item);
        }

        class Mapper {
            public static <T, R> void map(
                    Collection<? extends T> source,  // Producer
                    Collection<? super R> dest,      // Consumer
                    Function<? super T, ? extends R> mapper) {
                for (T item : source) {
                    R result = mapper.apply(item);
                    dest.add(result);
                }
            }
        }

        List<String> strings = Arrays.asList("1", "2", "3");
        List<Object> parsed = new ArrayList<>();

        Mapper.map(strings, parsed, Integer::parseInt);
        System.out.println("  Parsed: " + parsed);
    }
}
import java.util.*;

public class Pecs {
    static class Stack<E> {
        private List<E> elements = new ArrayList<>();

        public void push(E item) {
            elements.add(item);
        }

        public E pop() {
            if (elements.isEmpty()) {
                return null;
            }
            return elements.remove(elements.size() - 1);
        }

        // Producer - pushes items from src to this stack
        public void pushAll(Iterable<? extends E> src) {
            for (E item : src) {  // Reading from producer
                push(item);
            }
        }

        // Consumer - pops items from this stack to dst
        public void popAll(Collection<? super E> dst) {
            while (!elements.isEmpty()) {
                dst.add(pop());  // Writing to consumer
            }
        }

        public int size() {
            return elements.size();
        }
    }

    public static void main(String[] args) {
        System.out.println("PECS principle:\n");

        Stack<Number> numberStack = new Stack<>();

        // Producer Extends - can push from Integer list
        List<Integer> ints = Arrays.asList(1, 2, 3);
        numberStack.pushAll(ints);

        System.out.println("  Pushed integers, size: " + numberStack.size());

        // Consumer Super - can pop to Object list
        List<Object> objects = new ArrayList<>();
        numberStack.popAll(objects);

        System.out.println("  Popped to objects: " + objects);

        // PECS: Producer Extends, Consumer Super
        // Producer (reading): use <? extends T>
        // Consumer (writing): use <? super T>
        // Maximizes flexibility while maintaining type safety

        System.out.println("\nCollection utilities:");

        class CollectionUtils {
            // Producer - reading from source
            public static <T> void copy(
                    List<? super T> dest,      // Consumer - writing
                    List<? extends T> src) {   // Producer - reading
                dest.clear();
                for (T item : src) {
                    dest.add(item);
                }
            }

            // Producer - reading from multiple sources
            public static <T> void addAll(
                    Collection<? super T> dest,  // Consumer
                    Collection<? extends T>... sources) {  // Producers
                for (Collection<? extends T> src : sources) {
                    for (T item : src) {
                        dest.add(item);
                    }
                }
            }
        }

        List<Integer> intList = Arrays.asList(1, 2, 3);
        List<Double> doubleList = Arrays.asList(1.5, 2.5);
        List<Number> numberList = new ArrayList<>();

        CollectionUtils.addAll(numberList, intList, doubleList);
        System.out.println("  Combined: " + numberList);

        System.out.println("\nFrequency counter:");

        class Counter {
            public static <T> int frequency(
                    Collection<? extends T> collection,  // Producer
                    T target) {
                int count = 0;
                for (T item : collection) {  // Reading
                    if (item != null && item.equals(target)) {
                        count++;
                    }
                }
                return count;
            }
        }

        List<Integer> numbers = Arrays.asList(1, 2, 3, 2, 1, 2);
        int frequencyTarget = 4;
        System.out.println("  Frequency of " + frequencyTarget + ": " +
                         Counter.frequency(numbers, frequencyTarget));

        System.out.println("\nMax with comparator:");

        class MaxFinder {
            public static <T> T max(
                    Collection<? extends T> coll,  // Producer - reading
                    Comparator<? super T> comp) {  // Consumer - comparing
                if (coll.isEmpty()) {
                    return null;
                }

                Iterator<? extends T> it = coll.iterator();
                T max = it.next();

                while (it.hasNext()) {
                    T item = it.next();
                    if (comp.compare(item, max) > 0) {
                        max = item;
                    }
                }
                return max;
            }
        }

        List<String> words = Arrays.asList("apple", "zoo", "banana");
        String maxWord = MaxFinder.max(words, String::compareTo);
        System.out.println("  Max word: " + maxWord);

        System.out.println("\nFilter:");

        interface Predicate<T> {
            boolean test(T item);
        }

        class Filter {
            public static <T> void removeIf(
                    Collection<? extends T> source,   // Producer - reading
                    Collection<? super T> dest,       // Consumer - writing
                    Predicate<? super T> filter) {    // Consumer - testing
                for (T item : source) {
                    if (!filter.test(item)) {
                        dest.add(item);
                    }
                }
            }
        }

        List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
        List<Number> evens = new ArrayList<>();

        Filter.removeIf(nums, evens, n -> n % 2 != 0);  // Keep evens
        System.out.println("  Even numbers: " + evens);

        System.out.println("\nMap transformation:");

        interface Function<T, R> {
            R apply(T item);
        }

        class Mapper {
            public static <T, R> void map(
                    Collection<? extends T> source,  // Producer
                    Collection<? super R> dest,      // Consumer
                    Function<? super T, ? extends R> mapper) {
                for (T item : source) {
                    R result = mapper.apply(item);
                    dest.add(result);
                }
            }
        }

        List<String> strings = Arrays.asList("1", "2", "3");
        List<Object> parsed = new ArrayList<>();

        Mapper.map(strings, parsed, Integer::parseInt);
        System.out.println("  Parsed: " + parsed);
    }
}
  1. public static void main(String[] args)

    37public static void main(String[] args) {38    System.out.println("PECS principle:\n");
    outputPECS principle:
    PECS principle:
  2. public void pushAll(Iterable<? extends E> src)

    18// Producer - pushes items from src to this stack19public void pushAll(Iterable<? extends E> src[1, 2, 3]) {20    for (E item : src) {  // Reading from producer
  3. for (E item : src)

    pass 1 of 3
    19public void pushAll(Iterable<? extends E> src) {20    for (E item1 : src[1, 2, 3]) {  // Reading from producer21        push(item1);22    }
    All 3 passes — pass 1 is the card above
    passitem
    11
    22
    33
  4. public void push(E item)

    pass 1 of 3
    7public void push(E item1) {8    elements.add(item1);9}
    All 3 passes — pass 1 is the card above
    passitem
    11
    22
    33
  5. push(item);

    20for (E item : src) {  // Reading from producer21    push(item1);22}
  6. push(item);

    20for (E item : src) {  // Reading from producer21    push(item2);22}
  7. push(item);

    20for (E item : src) {  // Reading from producer21    push(item3);22}
  8. System.out.println(" Pushed integers, size: " + numberStack.size());

    46System.out.println("  Pushed integers, size: " + numberStack.size());
  9. System.out.println(" Pushed integers, size: " + numberStack.size());

    46System.out.println("  Pushed integers, size: " + numberStack.size());
    output  Pushed integers, size: 3
  10. System.out.println(" Pushed integers, size: " + numberStack.size());

    46System.out.println("  Pushed integers, size: " + numberStack.size());
    output  Pushed integers, size: 3
  11. public void popAll(Collection<? super E> dst)

    25// Consumer - pops items from this stack to dst26public void popAll(Collection<? super E> dst[]) {27    while (!elements.isEmpty()) {
  12. dst.add(pop()); // Writing to consumer

    27while (!elements.isEmpty()) {28    dst.add(pop());  // Writing to consumer29}
  13. dst.add(pop()); // Writing to consumer

    27while (!elements.isEmpty()) {28    dst.add(pop());  // Writing to consumer29}
  14. dst.add(pop()); // Writing to consumer

    27while (!elements.isEmpty()) {28    dst.add(pop());  // Writing to consumer29}
  15. System.out.println(" Popped to objects: " + objects);

    52System.out.println("  Popped to objects: " + objects[3, 2, 1]);5354// PECS: Producer Extends, Consumer Super55// Producer (reading): use <? extends T>56// Consumer (writing): use <? super T>57// Maximizes flexibility while maintaining type safety5859System.out.println("\nCollection utilities:");
    output  Popped to objects: [3, 2, 1]
      Popped to objects: [3, 2, 1]
    
    Collection utilities:
    
    Collection utilities:
  16. public static <T> void addAll( Collection<? super …

    72// Producer - reading from multiple sources73public static <T> void addAll(74        Collection<? super T> dest[],  // Consumer75        Collection<? extends T>... sources) {  // Producers76    for (Collection<? extends T> src : sources) {
  17. for (Collection<? extends T> src : sources)

    pass 1 of 2
    75    Collection<? extends T>... sources) {  // Producers76for (Collection<? extends T> src[1, 2, 3] : sources) {77    for (T item : src) {
  18. for (T item : src)

    pass 1 of 5
    76for (Collection<? extends T> src : sources) {77    for (T item1 : src[1, 2, 3]) {78        dest.add(item1);79    }
    All 5 passes — pass 1 is the card above
    passitemsrc
    11[1, 2, 3]
    22[1, 2, 3]
    33[1, 2, 3]
    41.5[1.5, 2.5]
    52.5[1.5, 2.5]
  19. for (Collection<? extends T> src : sources)

    pass 2 of 2
    75    Collection<? extends T>... sources) {  // Producers76for (Collection<? extends T> src[1.5, 2.5] : sources) {77    for (T item : src) {
  20. System.out.println(" Combined: " + numberList);

    88CollectionUtils.addAll(numberList, intList, doubleList);89System.out.println("  Combined: " + numberList[1, 2, 3, 1.5, 2.5]);9091System.out.println("\nFrequency counter:");9293class Counter {94    public static <T> int frequency(95            Collection<? extends T> collection,  // Producer96            T target) {97        int count = 0;98        for (T item : collection) {  // Reading99            if (item != null && item.equals(target)) {100                count++;101            }102        }103        return count;104    }105}106107List<Integer> numbers = Arrays.asList(1, 2, 3, 2, 1, 2);108int frequencyTarget = 2; //@frequencyTarget=2, 1, 4109System.out.println("  Frequency of " + frequencyTarget2 + ": " +110                 Counter.frequency(numbers[1, 2, 3, 2, 1, 2], frequencyTarget2));
    output  Combined: [1, 2, 3, 1.5, 2.5]
      Combined: [1, 2, 3, 1.5, 2.5]
    
    Frequency counter:
    
    Frequency counter:
  21. count ← 0

    pass 1 of 2
    93class Counter {94    public static <T> int frequency(95            Collection<? extends T> collection[1, 2, 3, 2, 1, 2],  // Producer96            T target2) {97        int count→ 0 = 0;98        for (T item : collection) {  // Reading
  22. for (T item : collection)

    pass 1 of 12
    97int count = 0;98for (T item1 : collection[1, 2, 3, 2, 1, 2]) {  // Reading99    if (item != null && item.equals(target)) {
    All 12 passes — pass 1 is the card above
    passitem
    11
    22
    33
    42
    51
    62
    71
    82
    93
    102
    111
    122
  23. count ← 1

    pass 1 of 6
    98for (T item : collection) {  // Reading99    if (item2 != null && item.equals(target2)) {100        count→ 1++;101    }
    All 6 passes — pass 1 is the card above
    passcount
    10 1
    21 2
    32 3
    40 1
    51 2
    62 3
  24. return count;

    102    }103    return count3;104}
  25. System.out.println(" Frequency of " + frequencyTarget + ": " +

    108int frequencyTarget = 2; //@frequencyTarget=2, 1, 4109System.out.println("  Frequency of " + frequencyTarget2 + ": " +110                 Counter.frequency(numbers[1, 2, 3, 2, 1, 2], frequencyTarget2));
    output  Frequency of 2: 3
  26. count ← 0

    pass 2 of 2
    93class Counter {94    public static <T> int frequency(95            Collection<? extends T> collection[1, 2, 3, 2, 1, 2],  // Producer96            T target2) {97        int count→ 0 = 0;98        for (T item : collection) {  // Reading
  27. return count;

    102    }103    return count3;104}
  28. System.out.println(" Frequency of " + frequencyTarget + ": " +

    108int frequencyTarget = 2; //@frequencyTarget=2, 1, 4109System.out.println("  Frequency of " + frequencyTarget2 + ": " +110                 Counter.frequency(numbers[1, 2, 3, 2, 1, 2], frequencyTarget2));111112System.out.println("\nMax with comparator:");113114class MaxFinder {115    public static <T> T max(116            Collection<? extends T> coll,  // Producer - reading117            Comparator<? super T> comp) {  // Consumer - comparing118        if (coll.isEmpty()) {119            return null;120        }121        122        Iterator<? extends T> it = coll.iterator();123        T max = it.next();124        125        while (it.hasNext()) {126            T item = it.next();127            if (comp.compare(item, max) > 0) {128                max = item;129            }130        }131        return max;132    }133}134135List<String> words = Arrays.asList("apple", "zoo", "banana");136String maxWord = MaxFinder.max(words[apple, zoo, banana], String::compareTo);137System.out.println("  Max word: " + maxWord);
    output  Frequency of 2: 3
    
    Max with comparator:
    
    Max with comparator:
  29. it ← ⟨Arrays$ArrayItr A⟩, max ← apple

    114class MaxFinder {115    public static <T> T max(116            Collection<? extends T> coll[apple, zoo, banana],  // Producer - reading117            Comparator<? super T> comp⟨Pecs lambda B⟩) {  // Consumer - comparing118        if (coll.isEmpty()) {119            return null;120        }121        122        Iterator<? extends T> it→ ⟨Arrays$ArrayItr A⟩ = coll.iterator();123        T max→ apple = it.next();
  30. item ← zoo

    pass 1 of 2
    125while (it.hasNext()) {126    T item→ zoo = it.next();127    if (comp.compare(item, max) > 0) {
  31. max ← zoo

    126T item = it.next();127if (comp.compare(itemzoo, maxapple) > 0) {128    max→ zoo = itemzoo;129}
  32. item ← banana

    pass 2 of 2
    125while (it.hasNext()) {126    T item→ banana = it.next();127    if (comp.compare(item, max) > 0) {
  33. return max;

    130    }131    return maxzoo;132}
  34. maxWord ← zoo, evens ← []

    135List<String> words = Arrays.asList("apple", "zoo", "banana");136String maxWord→ zoo = MaxFinder.max(words[apple, zoo, banana], String::compareTo);137System.out.println("  Max word: " + maxWordzoo);138139System.out.println("\nFilter:");140141interface Predicate<T> {142    boolean test(T item);143}144145class Filter {146    public static <T> void removeIf(147            Collection<? extends T> source,   // Producer - reading148            Collection<? super T> dest,       // Consumer - writing149            Predicate<? super T> filter) {    // Consumer - testing150        for (T item : source) {151            if (!filter.test(item)) {152                dest.add(item);153            }154        }155    }156}157158List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);159List<Number> evens→ [] = new ArrayList<>();160161Filter.removeIf(nums[1, 2, 3, 4, 5, 6], evens[], n -> n % 2 != 0);  // Keep evens162System.out.println("  Even numbers: " + evens);
    output  Max word: zoo
    
    Filter:
  35. public static <T> void removeIf( Collection<? exte…

    145class Filter {146    public static <T> void removeIf(147            Collection<? extends T> source[1, 2, 3, 4, 5, 6],   // Producer - reading148            Collection<? super T> dest[],       // Consumer - writing149            Predicate<? super T> filter⟨Pecs lambda C⟩) {    // Consumer - testing150        for (T item : source) {
  36. for (T item : source)

    pass 1 of 6
    149    Predicate<? super T> filter) {    // Consumer - testing150for (T item1 : source[1, 2, 3, 4, 5, 6]) {151    if (!filter.test(item)) {
    All 6 passes — pass 1 is the card above
    passitem
    11
    22
    33
    44
    55
    66
  37. if (!filter.test(item))

    pass 1 of 3
    150for (T item : source) {151    if (!filter.test(item2)) {152        dest.add(item2);153    }
    All 3 passes — pass 1 is the card above
    passitem
    12
    24
    36
  38. evens ← [2, 4, 6], parsed ← []

    161Filter.removeIf(nums[1, 2, 3, 4, 5, 6], evens→ [2, 4, 6], n -> n % 2 != 0);  // Keep evens162System.out.println("  Even numbers: " + evens[2, 4, 6]);163164System.out.println("\nMap transformation:");165166interface Function<T, R> {167    R apply(T item);168}169170class Mapper {171    public static <T, R> void map(172            Collection<? extends T> source,  // Producer173            Collection<? super R> dest,      // Consumer174            Function<? super T, ? extends R> mapper) {175        for (T item : source) {176            R result = mapper.apply(item);177            dest.add(result);178        }179    }180}181182List<String> strings = Arrays.asList("1", "2", "3");183List<Object> parsed→ [] = new ArrayList<>();184185Mapper.map(strings[1, 2, 3], parsed[], Integer::parseInt);186System.out.println("  Parsed: " + parsed);
    output  Even numbers: [2, 4, 6]
    
    Map transformation:
  39. public static <T, R> void map( Collection<? extend…

    170class Mapper {171    public static <T, R> void map(172            Collection<? extends T> source[1, 2, 3],  // Producer173            Collection<? super R> dest[],      // Consumer174            Function<? super T, ? extends R> mapper⟨Pecs lambda D⟩) {175        for (T item : source) {
  40. result ← 1

    pass 1 of 3
    174    Function<? super T, ? extends R> mapper) {175for (T item1 : source[1, 2, 3]) {176    R result→ 1 = mapper.apply(item1);177    dest.add(result1);178}
    All 3 passes — pass 1 is the card above
    passitemresult
    111
    222
    333
  41. parsed ← [1, 2, 3]

    185    Mapper.map(strings[1, 2, 3], parsed→ [1, 2, 3], Integer::parseInt);186    System.out.println("  Parsed: " + parsed[1, 2, 3]);187}
    output  Parsed: [1, 2, 3]
  1. public static void main(String[] args)

    37public static void main(String[] args) {38    System.out.println("PECS principle:\n");
    outputPECS principle:
    PECS principle:
  2. public void pushAll(Iterable<? extends E> src)

    18// Producer - pushes items from src to this stack19public void pushAll(Iterable<? extends E> src[1, 2, 3]) {20    for (E item : src) {  // Reading from producer
  3. for (E item : src)

    pass 1 of 3
    19public void pushAll(Iterable<? extends E> src) {20    for (E item1 : src[1, 2, 3]) {  // Reading from producer21        push(item1);22    }
    All 3 passes — pass 1 is the card above
    passitem
    11
    22
    33
  4. public void push(E item)

    pass 1 of 3
    7public void push(E item1) {8    elements.add(item1);9}
    All 3 passes — pass 1 is the card above
    passitem
    11
    22
    33
  5. push(item);

    20for (E item : src) {  // Reading from producer21    push(item1);22}
  6. push(item);

    20for (E item : src) {  // Reading from producer21    push(item2);22}
  7. push(item);

    20for (E item : src) {  // Reading from producer21    push(item3);22}
  8. System.out.println(" Pushed integers, size: " + numberStack.size());

    46System.out.println("  Pushed integers, size: " + numberStack.size());
  9. System.out.println(" Pushed integers, size: " + numberStack.size());

    46System.out.println("  Pushed integers, size: " + numberStack.size());
    output  Pushed integers, size: 3
  10. System.out.println(" Pushed integers, size: " + numberStack.size());

    46System.out.println("  Pushed integers, size: " + numberStack.size());
    output  Pushed integers, size: 3
  11. public void popAll(Collection<? super E> dst)

    25// Consumer - pops items from this stack to dst26public void popAll(Collection<? super E> dst[]) {27    while (!elements.isEmpty()) {
  12. dst.add(pop()); // Writing to consumer

    27while (!elements.isEmpty()) {28    dst.add(pop());  // Writing to consumer29}
  13. dst.add(pop()); // Writing to consumer

    27while (!elements.isEmpty()) {28    dst.add(pop());  // Writing to consumer29}
  14. dst.add(pop()); // Writing to consumer

    27while (!elements.isEmpty()) {28    dst.add(pop());  // Writing to consumer29}
  15. System.out.println(" Popped to objects: " + objects);

    52System.out.println("  Popped to objects: " + objects[3, 2, 1]);5354// PECS: Producer Extends, Consumer Super55// Producer (reading): use <? extends T>56// Consumer (writing): use <? super T>57// Maximizes flexibility while maintaining type safety5859System.out.println("\nCollection utilities:");
    output  Popped to objects: [3, 2, 1]
      Popped to objects: [3, 2, 1]
    
    Collection utilities:
    
    Collection utilities:
  16. public static <T> void addAll( Collection<? super …

    72// Producer - reading from multiple sources73public static <T> void addAll(74        Collection<? super T> dest[],  // Consumer75        Collection<? extends T>... sources) {  // Producers76    for (Collection<? extends T> src : sources) {
  17. for (Collection<? extends T> src : sources)

    pass 1 of 2
    75    Collection<? extends T>... sources) {  // Producers76for (Collection<? extends T> src[1, 2, 3] : sources) {77    for (T item : src) {
  18. for (T item : src)

    pass 1 of 5
    76for (Collection<? extends T> src : sources) {77    for (T item1 : src[1, 2, 3]) {78        dest.add(item1);79    }
    All 5 passes — pass 1 is the card above
    passitemsrc
    11[1, 2, 3]
    22[1, 2, 3]
    33[1, 2, 3]
    41.5[1.5, 2.5]
    52.5[1.5, 2.5]
  19. for (Collection<? extends T> src : sources)

    pass 2 of 2
    75    Collection<? extends T>... sources) {  // Producers76for (Collection<? extends T> src[1.5, 2.5] : sources) {77    for (T item : src) {
  20. System.out.println(" Combined: " + numberList);

    88CollectionUtils.addAll(numberList, intList, doubleList);89System.out.println("  Combined: " + numberList[1, 2, 3, 1.5, 2.5]);9091System.out.println("\nFrequency counter:");9293class Counter {94    public static <T> int frequency(95            Collection<? extends T> collection,  // Producer96            T target) {97        int count = 0;98        for (T item : collection) {  // Reading99            if (item != null && item.equals(target)) {100                count++;101            }102        }103        return count;104    }105}106107List<Integer> numbers = Arrays.asList(1, 2, 3, 2, 1, 2);108int frequencyTarget = 1;109System.out.println("  Frequency of " + frequencyTarget1 + ": " +110                 Counter.frequency(numbers[1, 2, 3, 2, 1, 2], frequencyTarget1));
    output  Combined: [1, 2, 3, 1.5, 2.5]
      Combined: [1, 2, 3, 1.5, 2.5]
    
    Frequency counter:
    
    Frequency counter:
  21. count ← 0

    pass 1 of 2
    93class Counter {94    public static <T> int frequency(95            Collection<? extends T> collection[1, 2, 3, 2, 1, 2],  // Producer96            T target1) {97        int count→ 0 = 0;98        for (T item : collection) {  // Reading
  22. for (T item : collection)

    pass 1 of 12
    97int count = 0;98for (T item1 : collection[1, 2, 3, 2, 1, 2]) {  // Reading99    if (item != null && item.equals(target)) {
    All 12 passes — pass 1 is the card above
    passitem
    11
    22
    33
    42
    51
    62
    71
    82
    93
    102
    111
    122
  23. count ← 1

    pass 1 of 4
    98for (T item : collection) {  // Reading99    if (item1 != null && item.equals(target1)) {100        count→ 1++;101    }
    All 4 passes — pass 1 is the card above
    passcount
    10 1
    21 2
    30 1
    41 2
  24. return count;

    102    }103    return count2;104}
  25. System.out.println(" Frequency of " + frequencyTarget + ": " +

    108int frequencyTarget = 1;109System.out.println("  Frequency of " + frequencyTarget1 + ": " +110                 Counter.frequency(numbers[1, 2, 3, 2, 1, 2], frequencyTarget1));
    output  Frequency of 1: 2
  26. count ← 0

    pass 2 of 2
    93class Counter {94    public static <T> int frequency(95            Collection<? extends T> collection[1, 2, 3, 2, 1, 2],  // Producer96            T target1) {97        int count→ 0 = 0;98        for (T item : collection) {  // Reading
  27. return count;

    102    }103    return count2;104}
  28. System.out.println(" Frequency of " + frequencyTarget + ": " +

    108int frequencyTarget = 1;109System.out.println("  Frequency of " + frequencyTarget1 + ": " +110                 Counter.frequency(numbers[1, 2, 3, 2, 1, 2], frequencyTarget1));111112System.out.println("\nMax with comparator:");113114class MaxFinder {115    public static <T> T max(116            Collection<? extends T> coll,  // Producer - reading117            Comparator<? super T> comp) {  // Consumer - comparing118        if (coll.isEmpty()) {119            return null;120        }121        122        Iterator<? extends T> it = coll.iterator();123        T max = it.next();124        125        while (it.hasNext()) {126            T item = it.next();127            if (comp.compare(item, max) > 0) {128                max = item;129            }130        }131        return max;132    }133}134135List<String> words = Arrays.asList("apple", "zoo", "banana");136String maxWord = MaxFinder.max(words[apple, zoo, banana], String::compareTo);137System.out.println("  Max word: " + maxWord);
    output  Frequency of 1: 2
    
    Max with comparator:
    
    Max with comparator:
  29. it ← ⟨Arrays$ArrayItr A⟩, max ← apple

    114class MaxFinder {115    public static <T> T max(116            Collection<? extends T> coll[apple, zoo, banana],  // Producer - reading117            Comparator<? super T> comp⟨Pecs lambda B⟩) {  // Consumer - comparing118        if (coll.isEmpty()) {119            return null;120        }121        122        Iterator<? extends T> it→ ⟨Arrays$ArrayItr A⟩ = coll.iterator();123        T max→ apple = it.next();
  30. item ← zoo

    pass 1 of 2
    125while (it.hasNext()) {126    T item→ zoo = it.next();127    if (comp.compare(item, max) > 0) {
  31. max ← zoo

    126T item = it.next();127if (comp.compare(itemzoo, maxapple) > 0) {128    max→ zoo = itemzoo;129}
  32. item ← banana

    pass 2 of 2
    125while (it.hasNext()) {126    T item→ banana = it.next();127    if (comp.compare(item, max) > 0) {
  33. return max;

    130    }131    return maxzoo;132}
  34. maxWord ← zoo, evens ← []

    135List<String> words = Arrays.asList("apple", "zoo", "banana");136String maxWord→ zoo = MaxFinder.max(words[apple, zoo, banana], String::compareTo);137System.out.println("  Max word: " + maxWordzoo);138139System.out.println("\nFilter:");140141interface Predicate<T> {142    boolean test(T item);143}144145class Filter {146    public static <T> void removeIf(147            Collection<? extends T> source,   // Producer - reading148            Collection<? super T> dest,       // Consumer - writing149            Predicate<? super T> filter) {    // Consumer - testing150        for (T item : source) {151            if (!filter.test(item)) {152                dest.add(item);153            }154        }155    }156}157158List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);159List<Number> evens→ [] = new ArrayList<>();160161Filter.removeIf(nums[1, 2, 3, 4, 5, 6], evens[], n -> n % 2 != 0);  // Keep evens162System.out.println("  Even numbers: " + evens);
    output  Max word: zoo
    
    Filter:
  35. public static <T> void removeIf( Collection<? exte…

    145class Filter {146    public static <T> void removeIf(147            Collection<? extends T> source[1, 2, 3, 4, 5, 6],   // Producer - reading148            Collection<? super T> dest[],       // Consumer - writing149            Predicate<? super T> filter⟨Pecs lambda C⟩) {    // Consumer - testing150        for (T item : source) {
  36. for (T item : source)

    pass 1 of 6
    149    Predicate<? super T> filter) {    // Consumer - testing150for (T item1 : source[1, 2, 3, 4, 5, 6]) {151    if (!filter.test(item)) {
    All 6 passes — pass 1 is the card above
    passitem
    11
    22
    33
    44
    55
    66
  37. if (!filter.test(item))

    pass 1 of 3
    150for (T item : source) {151    if (!filter.test(item2)) {152        dest.add(item2);153    }
    All 3 passes — pass 1 is the card above
    passitem
    12
    24
    36
  38. evens ← [2, 4, 6], parsed ← []

    161Filter.removeIf(nums[1, 2, 3, 4, 5, 6], evens→ [2, 4, 6], n -> n % 2 != 0);  // Keep evens162System.out.println("  Even numbers: " + evens[2, 4, 6]);163164System.out.println("\nMap transformation:");165166interface Function<T, R> {167    R apply(T item);168}169170class Mapper {171    public static <T, R> void map(172            Collection<? extends T> source,  // Producer173            Collection<? super R> dest,      // Consumer174            Function<? super T, ? extends R> mapper) {175        for (T item : source) {176            R result = mapper.apply(item);177            dest.add(result);178        }179    }180}181182List<String> strings = Arrays.asList("1", "2", "3");183List<Object> parsed→ [] = new ArrayList<>();184185Mapper.map(strings[1, 2, 3], parsed[], Integer::parseInt);186System.out.println("  Parsed: " + parsed);
    output  Even numbers: [2, 4, 6]
    
    Map transformation:
  39. public static <T, R> void map( Collection<? extend…

    170class Mapper {171    public static <T, R> void map(172            Collection<? extends T> source[1, 2, 3],  // Producer173            Collection<? super R> dest[],      // Consumer174            Function<? super T, ? extends R> mapper⟨Pecs lambda D⟩) {175        for (T item : source) {
  40. result ← 1

    pass 1 of 3
    174    Function<? super T, ? extends R> mapper) {175for (T item1 : source[1, 2, 3]) {176    R result→ 1 = mapper.apply(item1);177    dest.add(result1);178}
    All 3 passes — pass 1 is the card above
    passitemresult
    111
    222
    333
  41. parsed ← [1, 2, 3]

    185    Mapper.map(strings[1, 2, 3], parsed→ [1, 2, 3], Integer::parseInt);186    System.out.println("  Parsed: " + parsed[1, 2, 3]);187}
    output  Parsed: [1, 2, 3]
  1. public static void main(String[] args)

    37public static void main(String[] args) {38    System.out.println("PECS principle:\n");
    outputPECS principle:
    PECS principle:
  2. public void pushAll(Iterable<? extends E> src)

    18// Producer - pushes items from src to this stack19public void pushAll(Iterable<? extends E> src[1, 2, 3]) {20    for (E item : src) {  // Reading from producer
  3. for (E item : src)

    pass 1 of 3
    19public void pushAll(Iterable<? extends E> src) {20    for (E item1 : src[1, 2, 3]) {  // Reading from producer21        push(item1);22    }
    All 3 passes — pass 1 is the card above
    passitem
    11
    22
    33
  4. public void push(E item)

    pass 1 of 3
    7public void push(E item1) {8    elements.add(item1);9}
    All 3 passes — pass 1 is the card above
    passitem
    11
    22
    33
  5. push(item);

    20for (E item : src) {  // Reading from producer21    push(item1);22}
  6. push(item);

    20for (E item : src) {  // Reading from producer21    push(item2);22}
  7. push(item);

    20for (E item : src) {  // Reading from producer21    push(item3);22}
  8. System.out.println(" Pushed integers, size: " + numberStack.size());

    46System.out.println("  Pushed integers, size: " + numberStack.size());
  9. System.out.println(" Pushed integers, size: " + numberStack.size());

    46System.out.println("  Pushed integers, size: " + numberStack.size());
    output  Pushed integers, size: 3
  10. System.out.println(" Pushed integers, size: " + numberStack.size());

    46System.out.println("  Pushed integers, size: " + numberStack.size());
    output  Pushed integers, size: 3
  11. public void popAll(Collection<? super E> dst)

    25// Consumer - pops items from this stack to dst26public void popAll(Collection<? super E> dst[]) {27    while (!elements.isEmpty()) {
  12. dst.add(pop()); // Writing to consumer

    27while (!elements.isEmpty()) {28    dst.add(pop());  // Writing to consumer29}
  13. dst.add(pop()); // Writing to consumer

    27while (!elements.isEmpty()) {28    dst.add(pop());  // Writing to consumer29}
  14. dst.add(pop()); // Writing to consumer

    27while (!elements.isEmpty()) {28    dst.add(pop());  // Writing to consumer29}
  15. System.out.println(" Popped to objects: " + objects);

    52System.out.println("  Popped to objects: " + objects[3, 2, 1]);5354// PECS: Producer Extends, Consumer Super55// Producer (reading): use <? extends T>56// Consumer (writing): use <? super T>57// Maximizes flexibility while maintaining type safety5859System.out.println("\nCollection utilities:");
    output  Popped to objects: [3, 2, 1]
      Popped to objects: [3, 2, 1]
    
    Collection utilities:
    
    Collection utilities:
  16. public static <T> void addAll( Collection<? super …

    72// Producer - reading from multiple sources73public static <T> void addAll(74        Collection<? super T> dest[],  // Consumer75        Collection<? extends T>... sources) {  // Producers76    for (Collection<? extends T> src : sources) {
  17. for (Collection<? extends T> src : sources)

    pass 1 of 2
    75    Collection<? extends T>... sources) {  // Producers76for (Collection<? extends T> src[1, 2, 3] : sources) {77    for (T item : src) {
  18. for (T item : src)

    pass 1 of 5
    76for (Collection<? extends T> src : sources) {77    for (T item1 : src[1, 2, 3]) {78        dest.add(item1);79    }
    All 5 passes — pass 1 is the card above
    passitemsrc
    11[1, 2, 3]
    22[1, 2, 3]
    33[1, 2, 3]
    41.5[1.5, 2.5]
    52.5[1.5, 2.5]
  19. for (Collection<? extends T> src : sources)

    pass 2 of 2
    75    Collection<? extends T>... sources) {  // Producers76for (Collection<? extends T> src[1.5, 2.5] : sources) {77    for (T item : src) {
  20. System.out.println(" Combined: " + numberList);

    88CollectionUtils.addAll(numberList, intList, doubleList);89System.out.println("  Combined: " + numberList[1, 2, 3, 1.5, 2.5]);9091System.out.println("\nFrequency counter:");9293class Counter {94    public static <T> int frequency(95            Collection<? extends T> collection,  // Producer96            T target) {97        int count = 0;98        for (T item : collection) {  // Reading99            if (item != null && item.equals(target)) {100                count++;101            }102        }103        return count;104    }105}106107List<Integer> numbers = Arrays.asList(1, 2, 3, 2, 1, 2);108int frequencyTarget = 4;109System.out.println("  Frequency of " + frequencyTarget4 + ": " +110                 Counter.frequency(numbers[1, 2, 3, 2, 1, 2], frequencyTarget4));
    output  Combined: [1, 2, 3, 1.5, 2.5]
      Combined: [1, 2, 3, 1.5, 2.5]
    
    Frequency counter:
    
    Frequency counter:
  21. count ← 0

    pass 1 of 2
    93class Counter {94    public static <T> int frequency(95            Collection<? extends T> collection[1, 2, 3, 2, 1, 2],  // Producer96            T target4) {97        int count→ 0 = 0;98        for (T item : collection) {  // Reading
  22. for (T item : collection)

    pass 1 of 12
    97int count = 0;98for (T item1 : collection[1, 2, 3, 2, 1, 2]) {  // Reading99    if (item != null && item.equals(target)) {
    All 12 passes — pass 1 is the card above
    passitem
    11
    22
    33
    42
    51
    62
    71
    82
    93
    102
    111
    122
  23. return count;

    102    }103    return count0;104}
  24. System.out.println(" Frequency of " + frequencyTarget + ": " +

    108int frequencyTarget = 4;109System.out.println("  Frequency of " + frequencyTarget4 + ": " +110                 Counter.frequency(numbers[1, 2, 3, 2, 1, 2], frequencyTarget4));
    output  Frequency of 4: 0
  25. count ← 0

    pass 2 of 2
    93class Counter {94    public static <T> int frequency(95            Collection<? extends T> collection[1, 2, 3, 2, 1, 2],  // Producer96            T target4) {97        int count→ 0 = 0;98        for (T item : collection) {  // Reading
  26. return count;

    102    }103    return count0;104}
  27. System.out.println(" Frequency of " + frequencyTarget + ": " +

    108int frequencyTarget = 4;109System.out.println("  Frequency of " + frequencyTarget4 + ": " +110                 Counter.frequency(numbers[1, 2, 3, 2, 1, 2], frequencyTarget4));111112System.out.println("\nMax with comparator:");113114class MaxFinder {115    public static <T> T max(116            Collection<? extends T> coll,  // Producer - reading117            Comparator<? super T> comp) {  // Consumer - comparing118        if (coll.isEmpty()) {119            return null;120        }121        122        Iterator<? extends T> it = coll.iterator();123        T max = it.next();124        125        while (it.hasNext()) {126            T item = it.next();127            if (comp.compare(item, max) > 0) {128                max = item;129            }130        }131        return max;132    }133}134135List<String> words = Arrays.asList("apple", "zoo", "banana");136String maxWord = MaxFinder.max(words[apple, zoo, banana], String::compareTo);137System.out.println("  Max word: " + maxWord);
    output  Frequency of 4: 0
    
    Max with comparator:
    
    Max with comparator:
  28. it ← ⟨Arrays$ArrayItr A⟩, max ← apple

    114class MaxFinder {115    public static <T> T max(116            Collection<? extends T> coll[apple, zoo, banana],  // Producer - reading117            Comparator<? super T> comp⟨Pecs lambda B⟩) {  // Consumer - comparing118        if (coll.isEmpty()) {119            return null;120        }121        122        Iterator<? extends T> it→ ⟨Arrays$ArrayItr A⟩ = coll.iterator();123        T max→ apple = it.next();
  29. item ← zoo

    pass 1 of 2
    125while (it.hasNext()) {126    T item→ zoo = it.next();127    if (comp.compare(item, max) > 0) {
  30. max ← zoo

    126T item = it.next();127if (comp.compare(itemzoo, maxapple) > 0) {128    max→ zoo = itemzoo;129}
  31. item ← banana

    pass 2 of 2
    125while (it.hasNext()) {126    T item→ banana = it.next();127    if (comp.compare(item, max) > 0) {
  32. return max;

    130    }131    return maxzoo;132}
  33. maxWord ← zoo, evens ← []

    135List<String> words = Arrays.asList("apple", "zoo", "banana");136String maxWord→ zoo = MaxFinder.max(words[apple, zoo, banana], String::compareTo);137System.out.println("  Max word: " + maxWordzoo);138139System.out.println("\nFilter:");140141interface Predicate<T> {142    boolean test(T item);143}144145class Filter {146    public static <T> void removeIf(147            Collection<? extends T> source,   // Producer - reading148            Collection<? super T> dest,       // Consumer - writing149            Predicate<? super T> filter) {    // Consumer - testing150        for (T item : source) {151            if (!filter.test(item)) {152                dest.add(item);153            }154        }155    }156}157158List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);159List<Number> evens→ [] = new ArrayList<>();160161Filter.removeIf(nums[1, 2, 3, 4, 5, 6], evens[], n -> n % 2 != 0);  // Keep evens162System.out.println("  Even numbers: " + evens);
    output  Max word: zoo
    
    Filter:
  34. public static <T> void removeIf( Collection<? exte…

    145class Filter {146    public static <T> void removeIf(147            Collection<? extends T> source[1, 2, 3, 4, 5, 6],   // Producer - reading148            Collection<? super T> dest[],       // Consumer - writing149            Predicate<? super T> filter⟨Pecs lambda C⟩) {    // Consumer - testing150        for (T item : source) {
  35. for (T item : source)

    pass 1 of 6
    149    Predicate<? super T> filter) {    // Consumer - testing150for (T item1 : source[1, 2, 3, 4, 5, 6]) {151    if (!filter.test(item)) {
    All 6 passes — pass 1 is the card above
    passitem
    11
    22
    33
    44
    55
    66
  36. if (!filter.test(item))

    pass 1 of 3
    150for (T item : source) {151    if (!filter.test(item2)) {152        dest.add(item2);153    }
    All 3 passes — pass 1 is the card above
    passitem
    12
    24
    36
  37. evens ← [2, 4, 6], parsed ← []

    161Filter.removeIf(nums[1, 2, 3, 4, 5, 6], evens→ [2, 4, 6], n -> n % 2 != 0);  // Keep evens162System.out.println("  Even numbers: " + evens[2, 4, 6]);163164System.out.println("\nMap transformation:");165166interface Function<T, R> {167    R apply(T item);168}169170class Mapper {171    public static <T, R> void map(172            Collection<? extends T> source,  // Producer173            Collection<? super R> dest,      // Consumer174            Function<? super T, ? extends R> mapper) {175        for (T item : source) {176            R result = mapper.apply(item);177            dest.add(result);178        }179    }180}181182List<String> strings = Arrays.asList("1", "2", "3");183List<Object> parsed→ [] = new ArrayList<>();184185Mapper.map(strings[1, 2, 3], parsed[], Integer::parseInt);186System.out.println("  Parsed: " + parsed);
    output  Even numbers: [2, 4, 6]
    
    Map transformation:
  38. public static <T, R> void map( Collection<? extend…

    170class Mapper {171    public static <T, R> void map(172            Collection<? extends T> source[1, 2, 3],  // Producer173            Collection<? super R> dest[],      // Consumer174            Function<? super T, ? extends R> mapper⟨Pecs lambda D⟩) {175        for (T item : source) {
  39. result ← 1

    pass 1 of 3
    174    Function<? super T, ? extends R> mapper) {175for (T item1 : source[1, 2, 3]) {176    R result→ 1 = mapper.apply(item1);177    dest.add(result1);178}
    All 3 passes — pass 1 is the card above
    passitemresult
    111
    222
    333
  40. parsed ← [1, 2, 3]

    185    Mapper.map(strings[1, 2, 3], parsed→ [1, 2, 3], Integer::parseInt);186    System.out.println("  Parsed: " + parsed[1, 2, 3]);187}
    output  Parsed: [1, 2, 3]

Read from ? extends. Write to ? super. Copy: src extends, dest super.

PECS Producer Extends, Consumer Super. Guides wildcard choice for read vs write.

Wildcard capture

Convert wildcard to concrete type.

rotateDistance
Capture.java
Replay: real traced execution (multi-file project)
import java.util.*;

public class Capture {
    public static void reverse(List<?> list) {
        reverseHelper(list);  // Capture wildcard
    }

    private static <T> void reverseHelper(List<T> list) {
        // Now T is a concrete captured type
        int size = list.size();
        for (int i = 0; i < size / 2; i++) {
            T temp = list.get(i);
            list.set(i, list.get(size - 1 - i));
            list.set(size - 1 - i, temp);
        }
    }

    public static void main(String[] args) {
        System.out.println("Wildcard capture:\n");

        List<Integer> ints = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
        System.out.println("  Before: " + ints);
        reverse(ints);
        System.out.println("  After: " + ints);

        List<String> strs = new ArrayList<>(Arrays.asList("a", "b", "c"));
        System.out.println("  Before: " + strs);
        reverse(strs);
        System.out.println("  After: " + strs);

        // Cannot manipulate elements in List<?> directly
        // Use helper method with <T> to "capture" the type
        // Helper method sees concrete type T
        // Enables operations that need consistent type

        System.out.println("\nSwap elements:");

        class Swapper {
            public static void swap(List<?> list, int i, int j) {
                swapHelper(list, i, j);
            }

            private static <T> void swapHelper(List<T> list, int i, int j) {
                T temp = list.get(i);
                list.set(i, list.get(j));
                list.set(j, temp);
            }
        }

        List<Integer> numbers = new ArrayList<>(Arrays.asList(10, 20, 30, 40));
        System.out.println("  Before: " + numbers);
        Swapper.swap(numbers, 0, 3);
        System.out.println("  After: " + numbers);

        System.out.println("\nRotate list:");

        class Rotator {
            public static void rotate(List<?> list, int distance) {
                rotateHelper(list, distance);
            }

            private static <T> void rotateHelper(List<T> list, int distance) {
                int size = list.size();
                if (size == 0) return;

                distance = distance % size;
                if (distance < 0) distance += size;

                for (int i = 0; i < distance; i++) {
                    T last = list.remove(size - 1);
                    list.add(0, last);
                }
            }
        }

        List<String> words = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));
        System.out.println("  Before: " + words);
        int rotateDistance = 2;
        Rotator.rotate(words, rotateDistance);
        System.out.println("  After: " + words);

        System.out.println("\nShuffle:");

        class Shuffler {
            public static void shuffle(List<?> list) {
                shuffleHelper(list);
            }

            private static <T> void shuffleHelper(List<T> list) {
                Random random = new Random(42);
                for (int i = list.size() - 1; i > 0; i--) {
                    int j = random.nextInt(i + 1);
                    T temp = list.get(i);
                    list.set(i, list.get(j));
                    list.set(j, temp);
                }
            }
        }

        List<Integer> deck = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
        System.out.println("  Before: " + deck);
        Shuffler.shuffle(deck);
        System.out.println("  After: " + deck);

        System.out.println("\nFill with default:");

        class Filler {
            public static void fillWithDefault(List<?> list) {
                fillHelper(list);
            }

            private static <T> void fillHelper(List<T> list) {
                // Fill with null (default for reference types)
                for (int i = 0; i < list.size(); i++) {
                    list.set(i, null);
                }
            }
        }

        List<String> data = new ArrayList<>(Arrays.asList("x", "y", "z"));
        System.out.println("  Before: " + data);
        Filler.fillWithDefault(data);
        System.out.println("  After: " + data);

        System.out.println("\nRemove duplicates:");

        class Deduplicator {
            public static void removeDuplicates(List<?> list) {
                removeDuplicatesHelper(list);
            }

            private static <T> void removeDuplicatesHelper(List<T> list) {
                Set<T> seen = new HashSet<>();
                Iterator<T> it = list.iterator();
                while (it.hasNext()) {
                    T item = it.next();
                    if (!seen.add(item)) {
                        it.remove();
                    }
                }
            }
        }

        List<Integer> duplicates = new ArrayList<>(
            Arrays.asList(1, 2, 2, 3, 1, 4, 3, 5));
        System.out.println("  Before: " + duplicates);
        Deduplicator.removeDuplicates(duplicates);
        System.out.println("  After: " + duplicates);
    }
}
import java.util.*;

public class Capture {
    public static void reverse(List<?> list) {
        reverseHelper(list);  // Capture wildcard
    }

    private static <T> void reverseHelper(List<T> list) {
        // Now T is a concrete captured type
        int size = list.size();
        for (int i = 0; i < size / 2; i++) {
            T temp = list.get(i);
            list.set(i, list.get(size - 1 - i));
            list.set(size - 1 - i, temp);
        }
    }

    public static void main(String[] args) {
        System.out.println("Wildcard capture:\n");

        List<Integer> ints = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
        System.out.println("  Before: " + ints);
        reverse(ints);
        System.out.println("  After: " + ints);

        List<String> strs = new ArrayList<>(Arrays.asList("a", "b", "c"));
        System.out.println("  Before: " + strs);
        reverse(strs);
        System.out.println("  After: " + strs);

        // Cannot manipulate elements in List<?> directly
        // Use helper method with <T> to "capture" the type
        // Helper method sees concrete type T
        // Enables operations that need consistent type

        System.out.println("\nSwap elements:");

        class Swapper {
            public static void swap(List<?> list, int i, int j) {
                swapHelper(list, i, j);
            }

            private static <T> void swapHelper(List<T> list, int i, int j) {
                T temp = list.get(i);
                list.set(i, list.get(j));
                list.set(j, temp);
            }
        }

        List<Integer> numbers = new ArrayList<>(Arrays.asList(10, 20, 30, 40));
        System.out.println("  Before: " + numbers);
        Swapper.swap(numbers, 0, 3);
        System.out.println("  After: " + numbers);

        System.out.println("\nRotate list:");

        class Rotator {
            public static void rotate(List<?> list, int distance) {
                rotateHelper(list, distance);
            }

            private static <T> void rotateHelper(List<T> list, int distance) {
                int size = list.size();
                if (size == 0) return;

                distance = distance % size;
                if (distance < 0) distance += size;

                for (int i = 0; i < distance; i++) {
                    T last = list.remove(size - 1);
                    list.add(0, last);
                }
            }
        }

        List<String> words = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));
        System.out.println("  Before: " + words);
        int rotateDistance = -1;
        Rotator.rotate(words, rotateDistance);
        System.out.println("  After: " + words);

        System.out.println("\nShuffle:");

        class Shuffler {
            public static void shuffle(List<?> list) {
                shuffleHelper(list);
            }

            private static <T> void shuffleHelper(List<T> list) {
                Random random = new Random(42);
                for (int i = list.size() - 1; i > 0; i--) {
                    int j = random.nextInt(i + 1);
                    T temp = list.get(i);
                    list.set(i, list.get(j));
                    list.set(j, temp);
                }
            }
        }

        List<Integer> deck = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
        System.out.println("  Before: " + deck);
        Shuffler.shuffle(deck);
        System.out.println("  After: " + deck);

        System.out.println("\nFill with default:");

        class Filler {
            public static void fillWithDefault(List<?> list) {
                fillHelper(list);
            }

            private static <T> void fillHelper(List<T> list) {
                // Fill with null (default for reference types)
                for (int i = 0; i < list.size(); i++) {
                    list.set(i, null);
                }
            }
        }

        List<String> data = new ArrayList<>(Arrays.asList("x", "y", "z"));
        System.out.println("  Before: " + data);
        Filler.fillWithDefault(data);
        System.out.println("  After: " + data);

        System.out.println("\nRemove duplicates:");

        class Deduplicator {
            public static void removeDuplicates(List<?> list) {
                removeDuplicatesHelper(list);
            }

            private static <T> void removeDuplicatesHelper(List<T> list) {
                Set<T> seen = new HashSet<>();
                Iterator<T> it = list.iterator();
                while (it.hasNext()) {
                    T item = it.next();
                    if (!seen.add(item)) {
                        it.remove();
                    }
                }
            }
        }

        List<Integer> duplicates = new ArrayList<>(
            Arrays.asList(1, 2, 2, 3, 1, 4, 3, 5));
        System.out.println("  Before: " + duplicates);
        Deduplicator.removeDuplicates(duplicates);
        System.out.println("  After: " + duplicates);
    }
}
import java.util.*;

public class Capture {
    public static void reverse(List<?> list) {
        reverseHelper(list);  // Capture wildcard
    }

    private static <T> void reverseHelper(List<T> list) {
        // Now T is a concrete captured type
        int size = list.size();
        for (int i = 0; i < size / 2; i++) {
            T temp = list.get(i);
            list.set(i, list.get(size - 1 - i));
            list.set(size - 1 - i, temp);
        }
    }

    public static void main(String[] args) {
        System.out.println("Wildcard capture:\n");

        List<Integer> ints = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
        System.out.println("  Before: " + ints);
        reverse(ints);
        System.out.println("  After: " + ints);

        List<String> strs = new ArrayList<>(Arrays.asList("a", "b", "c"));
        System.out.println("  Before: " + strs);
        reverse(strs);
        System.out.println("  After: " + strs);

        // Cannot manipulate elements in List<?> directly
        // Use helper method with <T> to "capture" the type
        // Helper method sees concrete type T
        // Enables operations that need consistent type

        System.out.println("\nSwap elements:");

        class Swapper {
            public static void swap(List<?> list, int i, int j) {
                swapHelper(list, i, j);
            }

            private static <T> void swapHelper(List<T> list, int i, int j) {
                T temp = list.get(i);
                list.set(i, list.get(j));
                list.set(j, temp);
            }
        }

        List<Integer> numbers = new ArrayList<>(Arrays.asList(10, 20, 30, 40));
        System.out.println("  Before: " + numbers);
        Swapper.swap(numbers, 0, 3);
        System.out.println("  After: " + numbers);

        System.out.println("\nRotate list:");

        class Rotator {
            public static void rotate(List<?> list, int distance) {
                rotateHelper(list, distance);
            }

            private static <T> void rotateHelper(List<T> list, int distance) {
                int size = list.size();
                if (size == 0) return;

                distance = distance % size;
                if (distance < 0) distance += size;

                for (int i = 0; i < distance; i++) {
                    T last = list.remove(size - 1);
                    list.add(0, last);
                }
            }
        }

        List<String> words = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));
        System.out.println("  Before: " + words);
        int rotateDistance = 1;
        Rotator.rotate(words, rotateDistance);
        System.out.println("  After: " + words);

        System.out.println("\nShuffle:");

        class Shuffler {
            public static void shuffle(List<?> list) {
                shuffleHelper(list);
            }

            private static <T> void shuffleHelper(List<T> list) {
                Random random = new Random(42);
                for (int i = list.size() - 1; i > 0; i--) {
                    int j = random.nextInt(i + 1);
                    T temp = list.get(i);
                    list.set(i, list.get(j));
                    list.set(j, temp);
                }
            }
        }

        List<Integer> deck = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
        System.out.println("  Before: " + deck);
        Shuffler.shuffle(deck);
        System.out.println("  After: " + deck);

        System.out.println("\nFill with default:");

        class Filler {
            public static void fillWithDefault(List<?> list) {
                fillHelper(list);
            }

            private static <T> void fillHelper(List<T> list) {
                // Fill with null (default for reference types)
                for (int i = 0; i < list.size(); i++) {
                    list.set(i, null);
                }
            }
        }

        List<String> data = new ArrayList<>(Arrays.asList("x", "y", "z"));
        System.out.println("  Before: " + data);
        Filler.fillWithDefault(data);
        System.out.println("  After: " + data);

        System.out.println("\nRemove duplicates:");

        class Deduplicator {
            public static void removeDuplicates(List<?> list) {
                removeDuplicatesHelper(list);
            }

            private static <T> void removeDuplicatesHelper(List<T> list) {
                Set<T> seen = new HashSet<>();
                Iterator<T> it = list.iterator();
                while (it.hasNext()) {
                    T item = it.next();
                    if (!seen.add(item)) {
                        it.remove();
                    }
                }
            }
        }

        List<Integer> duplicates = new ArrayList<>(
            Arrays.asList(1, 2, 2, 3, 1, 4, 3, 5));
        System.out.println("  Before: " + duplicates);
        Deduplicator.removeDuplicates(duplicates);
        System.out.println("  After: " + duplicates);
    }
}
  1. public static void main(String[] args)

    18public static void main(String[] args) {19    System.out.println("Wildcard capture:\n");20    21    List<Integer> ints = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));22    System.out.println("  Before: " + ints[1, 2, 3, 4, 5]);23    reverse(ints);
    outputWildcard capture:
    Wildcard capture:
      Before: [1, 2, 3, 4, 5]
      Before: [1, 2, 3, 4, 5]
  2. public static void reverse(List<?> list)

    pass 1 of 2
    3public class Capture {4    public static void reverse(List<?> list[1, 2, 3, 4, 5]) {5        reverseHelper(list[1, 2, 3, 4, 5]);  // Capture wildcard6    }
  3. size ← 5

    pass 1 of 2
    8private static <T> void reverseHelper(List<T> list[1, 2, 3, 4, 5]) {9    // Now T is a concrete captured type10    int size→ 5 = list.size();11    for (int i = 0; i < size / 2; i++) {
  4. temp ← 1

    pass 1 of 3
    10int size = list.size();11for (int i0 = 0; i < size5 / 2; i++) {12    T temp→ 1 = list.get(i0);13    list.set(i0, list.get(size5 - 1 - i));14    list.set(size5 - 1 - i0, temp1);15}
    All 3 passes — pass 1 is the card above
    passisizetemplist
    1051
    2152[1, 2, 3, 4, 5] [5, 4, 3, 2, 1]
    303a[a, b, c] [c, b, a]
  5. System.out.println(" After: " + ints);

    23reverse(ints);24System.out.println("  After: " + ints[5, 4, 3, 2, 1]);2526List<String> strs = new ArrayList<>(Arrays.asList("a", "b", "c"));27System.out.println("  Before: " + strs[a, b, c]);28reverse(strs);
    output  After: [5, 4, 3, 2, 1]
      After: [5, 4, 3, 2, 1]
      Before: [a, b, c]
      Before: [a, b, c]
  6. public static void reverse(List<?> list)

    pass 2 of 2
    3public class Capture {4    public static void reverse(List<?> list[a, b, c]) {5        reverseHelper(list[a, b, c]);  // Capture wildcard6    }
  7. size ← 3

    pass 2 of 2
    8private static <T> void reverseHelper(List<T> list[a, b, c]) {9    // Now T is a concrete captured type10    int size→ 3 = list.size();11    for (int i = 0; i < size / 2; i++) {
  8. System.out.println(" After: " + strs);

    28reverse(strs);29System.out.println("  After: " + strs[c, b, a]);3031// Cannot manipulate elements in List<?> directly32// Use helper method with <T> to "capture" the type33// Helper method sees concrete type T34// Enables operations that need consistent type3536System.out.println("\nSwap elements:");3738class Swapper {39    public static void swap(List<?> list, int i, int j) {40        swapHelper(list, i, j);41    }42    43    private static <T> void swapHelper(List<T> list, int i, int j) {44        T temp = list.get(i);45        list.set(i, list.get(j));46        list.set(j, temp);47    }48}4950List<Integer> numbers = new ArrayList<>(Arrays.asList(10, 20, 30, 40));51System.out.println("  Before: " + numbers[10, 20, 30, 40]);52Swapper.swap(numbers, 0, 3);
    output  After: [c, b, a]
      After: [c, b, a]
    
    Swap elements:
    
    Swap elements:
      Before: [10, 20, 30, 40]
      Before: [10, 20, 30, 40]
  9. public static void swap(List<?> list, int i, int j)

    38class Swapper {39    public static void swap(List<?> list[10, 20, 30, 40], int i0, int j3) {40        swapHelper(list[10, 20, 30, 40], i0, j3);41    }
  10. temp ← 10, list ← [40, 20, 30, 10]

    39public static void swap(List<?> list, int i, int j) {40    swapHelper(list→ [40, 20, 30, 10], i0, j3);41}4243private static <T> void swapHelper(List<T> list[10, 20, 30, 40], int i0, int j3) {44    T temp→ 10 = list.get(i0);45    list.set(i0, list.get(j3));46    list.set(j3, temp10);47}
  11. System.out.println(" After: " + numbers);

    52Swapper.swap(numbers, 0, 3);53System.out.println("  After: " + numbers[40, 20, 30, 10]);5455System.out.println("\nRotate list:");5657class Rotator {58    public static void rotate(List<?> list, int distance) {59        rotateHelper(list, distance);60    }61    62    private static <T> void rotateHelper(List<T> list, int distance) {63        int size = list.size();64        if (size == 0) return;65        66        distance = distance % size;67        if (distance < 0) distance += size;68        69        for (int i = 0; i < distance; i++) {70            T last = list.remove(size - 1);71            list.add(0, last);72        }73    }74}7576List<String> words = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));77System.out.println("  Before: " + words[A, B, C, D, E]);78int rotateDistance = 2; //@rotateDistance=2, 1, -1
    output  After: [40, 20, 30, 10]
      After: [40, 20, 30, 10]
    
    Rotate list:
    
    Rotate list:
      Before: [A, B, C, D, E]
      Before: [A, B, C, D, E]
  12. public static void rotate(List<?> list, int distance)

    57class Rotator {58    public static void rotate(List<?> list[A, B, C, D, E], int distance2) {59        rotateHelper(list[A, B, C, D, E], distance2);60    }
  13. size ← 5, distance ← 2

    62private static <T> void rotateHelper(List<T> list[A, B, C, D, E], int distance2) {63    int size→ 5 = list.size();64    if (size == 0) return;65    66    distance→ 2 = distance % size5;67    if (distance < 0) distance += size;
  14. last ← E

    pass 1 of 2
    69for (int i0 = 0; i < distance2; i++) {70    T last→ E = list.remove(size5 - 1);71    list.add(0, lastE);72}
  15. last ← D, list ← [D, E, A, B, C]

    pass 2 of 2
    58public static void rotate(List<?> list, int distance) {59    rotateHelper(list→ [D, E, A, B, C], distance2);60}6162private static <T> void rotateHelper(List<T> list, int distance) {63    int size = list.size();64    if (size == 0) return;65    66    distance = distance % size;67    if (distance < 0) distance += size;68    69    for (int i1 = 0; i < distance2; i++) {70        T last→ D = list.remove(size5 - 1);71        list.add(0, lastD);72    }
  16. System.out.println(" After: " + words);

    79Rotator.rotate(words, rotateDistance);80System.out.println("  After: " + words[D, E, A, B, C]);8182System.out.println("\nShuffle:");8384class Shuffler {85    public static void shuffle(List<?> list) {86        shuffleHelper(list);87    }88    89    private static <T> void shuffleHelper(List<T> list) {90        Random random = new Random(42);91        for (int i = list.size() - 1; i > 0; i--) {92            int j = random.nextInt(i + 1);93            T temp = list.get(i);94            list.set(i, list.get(j));95            list.set(j, temp);96        }97    }98}99100List<Integer> deck = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));101System.out.println("  Before: " + deck[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);102Shuffler.shuffle(deck);
    output  After: [D, E, A, B, C]
      After: [D, E, A, B, C]
    
    Shuffle:
    
    Shuffle:
      Before: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
      Before: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  17. public static void shuffle(List<?> list)

    84class Shuffler {85    public static void shuffle(List<?> list[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) {86        shuffleHelper(list[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);87    }
  18. random ← ⟨Random A⟩

    89private static <T> void shuffleHelper(List<T> list[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) {90    Random random→ ⟨Random A⟩ = new Random(42);91    for (int i = list.size() - 1; i > 0; i--) {
  19. j ← 0, temp ← 10

    pass 1 of 9
    90Random random = new Random(42);91for (int i9 = list.size() - 1; i > 0; i--) {92    int j→ 0 = random.nextInt(i9 + 1);93    T temp→ 10 = list.get(i9);94    list.set(i9, list.get(j0));95    list.set(j0, temp10);96}
    All 9 passes — pass 1 is the card above
    passijtemplist
    19010
    2839
    3758
    4637
    5508
    6405
    7317
    8223
    9117[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] [5, 7, 3, 2, 8, 10, 9, 6, 4, 1]
  20. System.out.println(" After: " + deck);

    102Shuffler.shuffle(deck);103System.out.println("  After: " + deck[5, 7, 3, 2, 8, 10, 9, 6, 4, 1]);104105System.out.println("\nFill with default:");106107class Filler {108    public static void fillWithDefault(List<?> list) {109        fillHelper(list);110    }111    112    private static <T> void fillHelper(List<T> list) {113        // Fill with null (default for reference types)114        for (int i = 0; i < list.size(); i++) {115            list.set(i, null);116        }117    }118}119120List<String> data = new ArrayList<>(Arrays.asList("x", "y", "z"));121System.out.println("  Before: " + data[x, y, z]);122Filler.fillWithDefault(data);
    output  After: [5, 7, 3, 2, 8, 10, 9, 6, 4, 1]
      After: [5, 7, 3, 2, 8, 10, 9, 6, 4, 1]
    
    Fill with default:
    
    Fill with default:
      Before: [x, y, z]
      Before: [x, y, z]
  21. public static void fillWithDefault(List<?> list)

    107class Filler {108    public static void fillWithDefault(List<?> list[x, y, z]) {109        fillHelper(list[x, y, z]);110    }
  22. private static <T> void fillHelper(List<T> list)

    112private static <T> void fillHelper(List<T> list[x, y, z]) {113    // Fill with null (default for reference types)
  23. for (int i = 0; i < list.size(); i++)

    pass 1 of 3
    113// Fill with null (default for reference types)114for (int i0 = 0; i < list.size(); i++) {115    list.set(i0, null);116}
    All 3 passes — pass 1 is the card above
    passilist
    10
    21
    32[x, y, z] [null, null, null]
  24. System.out.println(" After: " + data);

    122Filler.fillWithDefault(data);123System.out.println("  After: " + data[null, null, null]);124125System.out.println("\nRemove duplicates:");126127class Deduplicator {128    public static void removeDuplicates(List<?> list) {129        removeDuplicatesHelper(list);130    }131    132    private static <T> void removeDuplicatesHelper(List<T> list) {133        Set<T> seen = new HashSet<>();134        Iterator<T> it = list.iterator();135        while (it.hasNext()) {136            T item = it.next();137            if (!seen.add(item)) {138                it.remove();139            }140        }141    }142}143144List<Integer> duplicates = new ArrayList<>(145    Arrays.asList(1, 2, 2, 3, 1, 4, 3, 5));146System.out.println("  Before: " + duplicates[1, 2, 2, 3, 1, 4, 3, 5]);147Deduplicator.removeDuplicates(duplicates[1, 2, 2, 3, 1, 4, 3, 5]);148System.out.println("  After: " + duplicates);
    output  After: [null, null, null]
      After: [null, null, null]
    
    Remove duplicates:
    
    Remove duplicates:
      Before: [1, 2, 2, 3, 1, 4, 3, 5]
  25. public static void removeDuplicates(List<?> list)

    127class Deduplicator {128    public static void removeDuplicates(List<?> list[1, 2, 2, 3, 1, 4, 3, 5]) {129        removeDuplicatesHelper(list[1, 2, 2, 3, 1, 4, 3, 5]);130    }
  26. seen ← [], it ← ⟨ArrayList$Itr B⟩

    132private static <T> void removeDuplicatesHelper(List<T> list[1, 2, 2, 3, 1, 4, 3, 5]) {133    Set<T> seen→ [] = new HashSet<>();134    Iterator<T> it→ ⟨ArrayList$Itr B⟩ = list.iterator();135    while (it.hasNext()) {
  27. item ← 1

    pass 1 of 8
    134Iterator<T> it = list.iterator();135while (it.hasNext()) {136    T item→ 1 = it.next();137    if (!seen.add(item)) {
    All 8 passes — pass 1 is the card above
    passitemlist
    11
    22
    32
    43
    51
    64
    73
    85[1, 2, 2, 3, 1, 4, 3, 5] [1, 2, 3, 4, 5]
  28. if (!seen.add(item))

    pass 1 of 3
    136T item = it.next();137if (!seen.add(item2)) {138    it.remove();139}
    All 3 passes — pass 1 is the card above
    passitem
    12
    21
    33
  29. duplicates ← [1, 2, 3, 4, 5]

    146    System.out.println("  Before: " + duplicates);147    Deduplicator.removeDuplicates(duplicates→ [1, 2, 3, 4, 5]);148    System.out.println("  After: " + duplicates[1, 2, 3, 4, 5]);149}
    output  After: [1, 2, 3, 4, 5]
  1. public static void main(String[] args)

    18public static void main(String[] args) {19    System.out.println("Wildcard capture:\n");20    21    List<Integer> ints = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));22    System.out.println("  Before: " + ints[1, 2, 3, 4, 5]);23    reverse(ints);
    outputWildcard capture:
    Wildcard capture:
      Before: [1, 2, 3, 4, 5]
      Before: [1, 2, 3, 4, 5]
  2. public static void reverse(List<?> list)

    pass 1 of 2
    3public class Capture {4    public static void reverse(List<?> list[1, 2, 3, 4, 5]) {5        reverseHelper(list[1, 2, 3, 4, 5]);  // Capture wildcard6    }
  3. size ← 5

    pass 1 of 2
    8private static <T> void reverseHelper(List<T> list[1, 2, 3, 4, 5]) {9    // Now T is a concrete captured type10    int size→ 5 = list.size();11    for (int i = 0; i < size / 2; i++) {
  4. temp ← 1

    pass 1 of 3
    10int size = list.size();11for (int i0 = 0; i < size5 / 2; i++) {12    T temp→ 1 = list.get(i0);13    list.set(i0, list.get(size5 - 1 - i));14    list.set(size5 - 1 - i0, temp1);15}
    All 3 passes — pass 1 is the card above
    passisizetemplist
    1051
    2152[1, 2, 3, 4, 5] [5, 4, 3, 2, 1]
    303a[a, b, c] [c, b, a]
  5. System.out.println(" After: " + ints);

    23reverse(ints);24System.out.println("  After: " + ints[5, 4, 3, 2, 1]);2526List<String> strs = new ArrayList<>(Arrays.asList("a", "b", "c"));27System.out.println("  Before: " + strs[a, b, c]);28reverse(strs);
    output  After: [5, 4, 3, 2, 1]
      After: [5, 4, 3, 2, 1]
      Before: [a, b, c]
      Before: [a, b, c]
  6. public static void reverse(List<?> list)

    pass 2 of 2
    3public class Capture {4    public static void reverse(List<?> list[a, b, c]) {5        reverseHelper(list[a, b, c]);  // Capture wildcard6    }
  7. size ← 3

    pass 2 of 2
    8private static <T> void reverseHelper(List<T> list[a, b, c]) {9    // Now T is a concrete captured type10    int size→ 3 = list.size();11    for (int i = 0; i < size / 2; i++) {
  8. System.out.println(" After: " + strs);

    28reverse(strs);29System.out.println("  After: " + strs[c, b, a]);3031// Cannot manipulate elements in List<?> directly32// Use helper method with <T> to "capture" the type33// Helper method sees concrete type T34// Enables operations that need consistent type3536System.out.println("\nSwap elements:");3738class Swapper {39    public static void swap(List<?> list, int i, int j) {40        swapHelper(list, i, j);41    }42    43    private static <T> void swapHelper(List<T> list, int i, int j) {44        T temp = list.get(i);45        list.set(i, list.get(j));46        list.set(j, temp);47    }48}4950List<Integer> numbers = new ArrayList<>(Arrays.asList(10, 20, 30, 40));51System.out.println("  Before: " + numbers[10, 20, 30, 40]);52Swapper.swap(numbers, 0, 3);
    output  After: [c, b, a]
      After: [c, b, a]
    
    Swap elements:
    
    Swap elements:
      Before: [10, 20, 30, 40]
      Before: [10, 20, 30, 40]
  9. public static void swap(List<?> list, int i, int j)

    38class Swapper {39    public static void swap(List<?> list[10, 20, 30, 40], int i0, int j3) {40        swapHelper(list[10, 20, 30, 40], i0, j3);41    }
  10. temp ← 10, list ← [40, 20, 30, 10]

    39public static void swap(List<?> list, int i, int j) {40    swapHelper(list→ [40, 20, 30, 10], i0, j3);41}4243private static <T> void swapHelper(List<T> list[10, 20, 30, 40], int i0, int j3) {44    T temp→ 10 = list.get(i0);45    list.set(i0, list.get(j3));46    list.set(j3, temp10);47}
  11. System.out.println(" After: " + numbers);

    52Swapper.swap(numbers, 0, 3);53System.out.println("  After: " + numbers[40, 20, 30, 10]);5455System.out.println("\nRotate list:");5657class Rotator {58    public static void rotate(List<?> list, int distance) {59        rotateHelper(list, distance);60    }61    62    private static <T> void rotateHelper(List<T> list, int distance) {63        int size = list.size();64        if (size == 0) return;65        66        distance = distance % size;67        if (distance < 0) distance += size;68        69        for (int i = 0; i < distance; i++) {70            T last = list.remove(size - 1);71            list.add(0, last);72        }73    }74}7576List<String> words = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));77System.out.println("  Before: " + words[A, B, C, D, E]);78int rotateDistance = -1;
    output  After: [40, 20, 30, 10]
      After: [40, 20, 30, 10]
    
    Rotate list:
    
    Rotate list:
      Before: [A, B, C, D, E]
      Before: [A, B, C, D, E]
  12. public static void rotate(List<?> list, int distance)

    57class Rotator {58    public static void rotate(List<?> list[A, B, C, D, E], int distance-1) {59        rotateHelper(list[A, B, C, D, E], distance-1);60    }
  13. size ← 5, distance ← -1

    62private static <T> void rotateHelper(List<T> list[A, B, C, D, E], int distance-1) {63    int size→ 5 = list.size();64    if (size == 0) return;65    66    distance→ -1 = distance % size5;67    if (distance < 0) distance += size;
  14. distance ← 4

    66distance = distance % size;67if (distance-1 < 0) distance += size5;
  15. last ← E

    pass 1 of 4
    69for (int i0 = 0; i < distance4; i++) {70    T last→ E = list.remove(size5 - 1);71    list.add(0, lastE);72}
    All 4 passes — pass 1 is the card above
    passilastlist
    10E
    21D
    32C
    43B[A, B, C, D, E] [B, C, D, E, A]
  16. System.out.println(" After: " + words);

    79Rotator.rotate(words, rotateDistance);80System.out.println("  After: " + words[B, C, D, E, A]);8182System.out.println("\nShuffle:");8384class Shuffler {85    public static void shuffle(List<?> list) {86        shuffleHelper(list);87    }88    89    private static <T> void shuffleHelper(List<T> list) {90        Random random = new Random(42);91        for (int i = list.size() - 1; i > 0; i--) {92            int j = random.nextInt(i + 1);93            T temp = list.get(i);94            list.set(i, list.get(j));95            list.set(j, temp);96        }97    }98}99100List<Integer> deck = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));101System.out.println("  Before: " + deck[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);102Shuffler.shuffle(deck);
    output  After: [B, C, D, E, A]
      After: [B, C, D, E, A]
    
    Shuffle:
    
    Shuffle:
      Before: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
      Before: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  17. public static void shuffle(List<?> list)

    84class Shuffler {85    public static void shuffle(List<?> list[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) {86        shuffleHelper(list[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);87    }
  18. random ← ⟨Random A⟩

    89private static <T> void shuffleHelper(List<T> list[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) {90    Random random→ ⟨Random A⟩ = new Random(42);91    for (int i = list.size() - 1; i > 0; i--) {
  19. j ← 0, temp ← 10

    pass 1 of 9
    90Random random = new Random(42);91for (int i9 = list.size() - 1; i > 0; i--) {92    int j→ 0 = random.nextInt(i9 + 1);93    T temp→ 10 = list.get(i9);94    list.set(i9, list.get(j0));95    list.set(j0, temp10);96}
    All 9 passes — pass 1 is the card above
    passijtemplist
    19010
    2839
    3758
    4637
    5508
    6405
    7317
    8223
    9117[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] [5, 7, 3, 2, 8, 10, 9, 6, 4, 1]
  20. System.out.println(" After: " + deck);

    102Shuffler.shuffle(deck);103System.out.println("  After: " + deck[5, 7, 3, 2, 8, 10, 9, 6, 4, 1]);104105System.out.println("\nFill with default:");106107class Filler {108    public static void fillWithDefault(List<?> list) {109        fillHelper(list);110    }111    112    private static <T> void fillHelper(List<T> list) {113        // Fill with null (default for reference types)114        for (int i = 0; i < list.size(); i++) {115            list.set(i, null);116        }117    }118}119120List<String> data = new ArrayList<>(Arrays.asList("x", "y", "z"));121System.out.println("  Before: " + data[x, y, z]);122Filler.fillWithDefault(data);
    output  After: [5, 7, 3, 2, 8, 10, 9, 6, 4, 1]
      After: [5, 7, 3, 2, 8, 10, 9, 6, 4, 1]
    
    Fill with default:
    
    Fill with default:
      Before: [x, y, z]
      Before: [x, y, z]
  21. public static void fillWithDefault(List<?> list)

    107class Filler {108    public static void fillWithDefault(List<?> list[x, y, z]) {109        fillHelper(list[x, y, z]);110    }
  22. private static <T> void fillHelper(List<T> list)

    112private static <T> void fillHelper(List<T> list[x, y, z]) {113    // Fill with null (default for reference types)
  23. for (int i = 0; i < list.size(); i++)

    pass 1 of 3
    113// Fill with null (default for reference types)114for (int i0 = 0; i < list.size(); i++) {115    list.set(i0, null);116}
    All 3 passes — pass 1 is the card above
    passilist
    10
    21
    32[x, y, z] [null, null, null]
  24. System.out.println(" After: " + data);

    122Filler.fillWithDefault(data);123System.out.println("  After: " + data[null, null, null]);124125System.out.println("\nRemove duplicates:");126127class Deduplicator {128    public static void removeDuplicates(List<?> list) {129        removeDuplicatesHelper(list);130    }131    132    private static <T> void removeDuplicatesHelper(List<T> list) {133        Set<T> seen = new HashSet<>();134        Iterator<T> it = list.iterator();135        while (it.hasNext()) {136            T item = it.next();137            if (!seen.add(item)) {138                it.remove();139            }140        }141    }142}143144List<Integer> duplicates = new ArrayList<>(145    Arrays.asList(1, 2, 2, 3, 1, 4, 3, 5));146System.out.println("  Before: " + duplicates[1, 2, 2, 3, 1, 4, 3, 5]);147Deduplicator.removeDuplicates(duplicates[1, 2, 2, 3, 1, 4, 3, 5]);148System.out.println("  After: " + duplicates);
    output  After: [null, null, null]
      After: [null, null, null]
    
    Remove duplicates:
    
    Remove duplicates:
      Before: [1, 2, 2, 3, 1, 4, 3, 5]
  25. public static void removeDuplicates(List<?> list)

    127class Deduplicator {128    public static void removeDuplicates(List<?> list[1, 2, 2, 3, 1, 4, 3, 5]) {129        removeDuplicatesHelper(list[1, 2, 2, 3, 1, 4, 3, 5]);130    }
  26. seen ← [], it ← ⟨ArrayList$Itr B⟩

    132private static <T> void removeDuplicatesHelper(List<T> list[1, 2, 2, 3, 1, 4, 3, 5]) {133    Set<T> seen→ [] = new HashSet<>();134    Iterator<T> it→ ⟨ArrayList$Itr B⟩ = list.iterator();135    while (it.hasNext()) {
  27. item ← 1

    pass 1 of 8
    134Iterator<T> it = list.iterator();135while (it.hasNext()) {136    T item→ 1 = it.next();137    if (!seen.add(item)) {
    All 8 passes — pass 1 is the card above
    passitemlist
    11
    22
    32
    43
    51
    64
    73
    85[1, 2, 2, 3, 1, 4, 3, 5] [1, 2, 3, 4, 5]
  28. if (!seen.add(item))

    pass 1 of 3
    136T item = it.next();137if (!seen.add(item2)) {138    it.remove();139}
    All 3 passes — pass 1 is the card above
    passitem
    12
    21
    33
  29. duplicates ← [1, 2, 3, 4, 5]

    146    System.out.println("  Before: " + duplicates);147    Deduplicator.removeDuplicates(duplicates→ [1, 2, 3, 4, 5]);148    System.out.println("  After: " + duplicates[1, 2, 3, 4, 5]);149}
    output  After: [1, 2, 3, 4, 5]
  1. public static void main(String[] args)

    18public static void main(String[] args) {19    System.out.println("Wildcard capture:\n");20    21    List<Integer> ints = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));22    System.out.println("  Before: " + ints[1, 2, 3, 4, 5]);23    reverse(ints);
    outputWildcard capture:
    Wildcard capture:
      Before: [1, 2, 3, 4, 5]
      Before: [1, 2, 3, 4, 5]
  2. public static void reverse(List<?> list)

    pass 1 of 2
    3public class Capture {4    public static void reverse(List<?> list[1, 2, 3, 4, 5]) {5        reverseHelper(list[1, 2, 3, 4, 5]);  // Capture wildcard6    }
  3. size ← 5

    pass 1 of 2
    8private static <T> void reverseHelper(List<T> list[1, 2, 3, 4, 5]) {9    // Now T is a concrete captured type10    int size→ 5 = list.size();11    for (int i = 0; i < size / 2; i++) {
  4. temp ← 1

    pass 1 of 3
    10int size = list.size();11for (int i0 = 0; i < size5 / 2; i++) {12    T temp→ 1 = list.get(i0);13    list.set(i0, list.get(size5 - 1 - i));14    list.set(size5 - 1 - i0, temp1);15}
    All 3 passes — pass 1 is the card above
    passisizetemplist
    1051
    2152[1, 2, 3, 4, 5] [5, 4, 3, 2, 1]
    303a[a, b, c] [c, b, a]
  5. System.out.println(" After: " + ints);

    23reverse(ints);24System.out.println("  After: " + ints[5, 4, 3, 2, 1]);2526List<String> strs = new ArrayList<>(Arrays.asList("a", "b", "c"));27System.out.println("  Before: " + strs[a, b, c]);28reverse(strs);
    output  After: [5, 4, 3, 2, 1]
      After: [5, 4, 3, 2, 1]
      Before: [a, b, c]
      Before: [a, b, c]
  6. public static void reverse(List<?> list)

    pass 2 of 2
    3public class Capture {4    public static void reverse(List<?> list[a, b, c]) {5        reverseHelper(list[a, b, c]);  // Capture wildcard6    }
  7. size ← 3

    pass 2 of 2
    8private static <T> void reverseHelper(List<T> list[a, b, c]) {9    // Now T is a concrete captured type10    int size→ 3 = list.size();11    for (int i = 0; i < size / 2; i++) {
  8. System.out.println(" After: " + strs);

    28reverse(strs);29System.out.println("  After: " + strs[c, b, a]);3031// Cannot manipulate elements in List<?> directly32// Use helper method with <T> to "capture" the type33// Helper method sees concrete type T34// Enables operations that need consistent type3536System.out.println("\nSwap elements:");3738class Swapper {39    public static void swap(List<?> list, int i, int j) {40        swapHelper(list, i, j);41    }42    43    private static <T> void swapHelper(List<T> list, int i, int j) {44        T temp = list.get(i);45        list.set(i, list.get(j));46        list.set(j, temp);47    }48}4950List<Integer> numbers = new ArrayList<>(Arrays.asList(10, 20, 30, 40));51System.out.println("  Before: " + numbers[10, 20, 30, 40]);52Swapper.swap(numbers, 0, 3);
    output  After: [c, b, a]
      After: [c, b, a]
    
    Swap elements:
    
    Swap elements:
      Before: [10, 20, 30, 40]
      Before: [10, 20, 30, 40]
  9. public static void swap(List<?> list, int i, int j)

    38class Swapper {39    public static void swap(List<?> list[10, 20, 30, 40], int i0, int j3) {40        swapHelper(list[10, 20, 30, 40], i0, j3);41    }
  10. temp ← 10, list ← [40, 20, 30, 10]

    39public static void swap(List<?> list, int i, int j) {40    swapHelper(list→ [40, 20, 30, 10], i0, j3);41}4243private static <T> void swapHelper(List<T> list[10, 20, 30, 40], int i0, int j3) {44    T temp→ 10 = list.get(i0);45    list.set(i0, list.get(j3));46    list.set(j3, temp10);47}
  11. System.out.println(" After: " + numbers);

    52Swapper.swap(numbers, 0, 3);53System.out.println("  After: " + numbers[40, 20, 30, 10]);5455System.out.println("\nRotate list:");5657class Rotator {58    public static void rotate(List<?> list, int distance) {59        rotateHelper(list, distance);60    }61    62    private static <T> void rotateHelper(List<T> list, int distance) {63        int size = list.size();64        if (size == 0) return;65        66        distance = distance % size;67        if (distance < 0) distance += size;68        69        for (int i = 0; i < distance; i++) {70            T last = list.remove(size - 1);71            list.add(0, last);72        }73    }74}7576List<String> words = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));77System.out.println("  Before: " + words[A, B, C, D, E]);78int rotateDistance = 1;
    output  After: [40, 20, 30, 10]
      After: [40, 20, 30, 10]
    
    Rotate list:
    
    Rotate list:
      Before: [A, B, C, D, E]
      Before: [A, B, C, D, E]
  12. public static void rotate(List<?> list, int distance)

    57class Rotator {58    public static void rotate(List<?> list[A, B, C, D, E], int distance1) {59        rotateHelper(list[A, B, C, D, E], distance1);60    }
  13. size ← 5, distance ← 1

    62private static <T> void rotateHelper(List<T> list[A, B, C, D, E], int distance1) {63    int size→ 5 = list.size();64    if (size == 0) return;65    66    distance→ 1 = distance % size5;67    if (distance < 0) distance += size;
  14. last ← E, list ← [E, A, B, C, D]

    58public static void rotate(List<?> list, int distance) {59    rotateHelper(list→ [E, A, B, C, D], distance1);60}6162private static <T> void rotateHelper(List<T> list, int distance) {63    int size = list.size();64    if (size == 0) return;65    66    distance = distance % size;67    if (distance < 0) distance += size;68    69    for (int i0 = 0; i < distance1; i++) {70        T last→ E = list.remove(size5 - 1);71        list.add(0, lastE);72    }
  15. System.out.println(" After: " + words);

    79Rotator.rotate(words, rotateDistance);80System.out.println("  After: " + words[E, A, B, C, D]);8182System.out.println("\nShuffle:");8384class Shuffler {85    public static void shuffle(List<?> list) {86        shuffleHelper(list);87    }88    89    private static <T> void shuffleHelper(List<T> list) {90        Random random = new Random(42);91        for (int i = list.size() - 1; i > 0; i--) {92            int j = random.nextInt(i + 1);93            T temp = list.get(i);94            list.set(i, list.get(j));95            list.set(j, temp);96        }97    }98}99100List<Integer> deck = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));101System.out.println("  Before: " + deck[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);102Shuffler.shuffle(deck);
    output  After: [E, A, B, C, D]
      After: [E, A, B, C, D]
    
    Shuffle:
    
    Shuffle:
      Before: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
      Before: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  16. public static void shuffle(List<?> list)

    84class Shuffler {85    public static void shuffle(List<?> list[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) {86        shuffleHelper(list[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);87    }
  17. random ← ⟨Random A⟩

    89private static <T> void shuffleHelper(List<T> list[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) {90    Random random→ ⟨Random A⟩ = new Random(42);91    for (int i = list.size() - 1; i > 0; i--) {
  18. j ← 0, temp ← 10

    pass 1 of 9
    90Random random = new Random(42);91for (int i9 = list.size() - 1; i > 0; i--) {92    int j→ 0 = random.nextInt(i9 + 1);93    T temp→ 10 = list.get(i9);94    list.set(i9, list.get(j0));95    list.set(j0, temp10);96}
    All 9 passes — pass 1 is the card above
    passijtemplist
    19010
    2839
    3758
    4637
    5508
    6405
    7317
    8223
    9117[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] [5, 7, 3, 2, 8, 10, 9, 6, 4, 1]
  19. System.out.println(" After: " + deck);

    102Shuffler.shuffle(deck);103System.out.println("  After: " + deck[5, 7, 3, 2, 8, 10, 9, 6, 4, 1]);104105System.out.println("\nFill with default:");106107class Filler {108    public static void fillWithDefault(List<?> list) {109        fillHelper(list);110    }111    112    private static <T> void fillHelper(List<T> list) {113        // Fill with null (default for reference types)114        for (int i = 0; i < list.size(); i++) {115            list.set(i, null);116        }117    }118}119120List<String> data = new ArrayList<>(Arrays.asList("x", "y", "z"));121System.out.println("  Before: " + data[x, y, z]);122Filler.fillWithDefault(data);
    output  After: [5, 7, 3, 2, 8, 10, 9, 6, 4, 1]
      After: [5, 7, 3, 2, 8, 10, 9, 6, 4, 1]
    
    Fill with default:
    
    Fill with default:
      Before: [x, y, z]
      Before: [x, y, z]
  20. public static void fillWithDefault(List<?> list)

    107class Filler {108    public static void fillWithDefault(List<?> list[x, y, z]) {109        fillHelper(list[x, y, z]);110    }
  21. private static <T> void fillHelper(List<T> list)

    112private static <T> void fillHelper(List<T> list[x, y, z]) {113    // Fill with null (default for reference types)
  22. for (int i = 0; i < list.size(); i++)

    pass 1 of 3
    113// Fill with null (default for reference types)114for (int i0 = 0; i < list.size(); i++) {115    list.set(i0, null);116}
    All 3 passes — pass 1 is the card above
    passilist
    10
    21
    32[x, y, z] [null, null, null]
  23. System.out.println(" After: " + data);

    122Filler.fillWithDefault(data);123System.out.println("  After: " + data[null, null, null]);124125System.out.println("\nRemove duplicates:");126127class Deduplicator {128    public static void removeDuplicates(List<?> list) {129        removeDuplicatesHelper(list);130    }131    132    private static <T> void removeDuplicatesHelper(List<T> list) {133        Set<T> seen = new HashSet<>();134        Iterator<T> it = list.iterator();135        while (it.hasNext()) {136            T item = it.next();137            if (!seen.add(item)) {138                it.remove();139            }140        }141    }142}143144List<Integer> duplicates = new ArrayList<>(145    Arrays.asList(1, 2, 2, 3, 1, 4, 3, 5));146System.out.println("  Before: " + duplicates[1, 2, 2, 3, 1, 4, 3, 5]);147Deduplicator.removeDuplicates(duplicates[1, 2, 2, 3, 1, 4, 3, 5]);148System.out.println("  After: " + duplicates);
    output  After: [null, null, null]
      After: [null, null, null]
    
    Remove duplicates:
    
    Remove duplicates:
      Before: [1, 2, 2, 3, 1, 4, 3, 5]
  24. public static void removeDuplicates(List<?> list)

    127class Deduplicator {128    public static void removeDuplicates(List<?> list[1, 2, 2, 3, 1, 4, 3, 5]) {129        removeDuplicatesHelper(list[1, 2, 2, 3, 1, 4, 3, 5]);130    }
  25. seen ← [], it ← ⟨ArrayList$Itr B⟩

    132private static <T> void removeDuplicatesHelper(List<T> list[1, 2, 2, 3, 1, 4, 3, 5]) {133    Set<T> seen→ [] = new HashSet<>();134    Iterator<T> it→ ⟨ArrayList$Itr B⟩ = list.iterator();135    while (it.hasNext()) {
  26. item ← 1

    pass 1 of 8
    134Iterator<T> it = list.iterator();135while (it.hasNext()) {136    T item→ 1 = it.next();137    if (!seen.add(item)) {
    All 8 passes — pass 1 is the card above
    passitemlist
    11
    22
    32
    43
    51
    64
    73
    85[1, 2, 2, 3, 1, 4, 3, 5] [1, 2, 3, 4, 5]
  27. if (!seen.add(item))

    pass 1 of 3
    136T item = it.next();137if (!seen.add(item2)) {138    it.remove();139}
    All 3 passes — pass 1 is the card above
    passitem
    12
    21
    33
  28. duplicates ← [1, 2, 3, 4, 5]

    146    System.out.println("  Before: " + duplicates);147    Deduplicator.removeDuplicates(duplicates→ [1, 2, 3, 4, 5]);148    System.out.println("  After: " + duplicates[1, 2, 3, 4, 5]);149}
    output  After: [1, 2, 3, 4, 5]

Helper method with type parameter captures the wildcard's actual type.

Exercise: Practical.java

Build a collection copier using PECS