为何Java Stream.map的入参是Function<? super P_OUT, ? extends R>而非Function<P_OUT, ? extends R>
Great question! Let's unpack this design choice and your follow-up questions with clear, practical examples.
1. The core reason for using ? super P_OUT
Java's generics wildcards exist to boost flexibility, and ? super P_OUT (a lower-bounded wildcard) here serves a critical purpose: it lets you reuse any Function that can accept P_OUT or any of its parent types.
If map() only accepted Function<P_OUT, ? extends R>, you'd be stuck using functions whose input type exactly matches the stream's element type. But with ? super P_OUT, you can pass functions built for broader types (like a parent class of P_OUT), since any instance of P_OUT is automatically an instance of its parent types. This drastically increases code reusability without losing type safety.
2. Why does this matter even when your stream uses Integer?
In your example List<Integer> list = new ArrayList<>(); list.stream().map(xyz -> {});, xyz is indeed always an Integer—but the wildcard isn't about the stream's elements, it's about the functions you can pass to map().
It's not just for method references
While method references are a common use case, they're far from the only scenario where this wildcard shines. Let's break down two key examples:
Scenario 1: Reusing a pre-defined Function
Suppose you have a function built to handle Number (the parent class of Integer):
Function<Number, String> numberToString = num -> String.format("Value: %d", num.longValue());
With ? super Integer, you can reuse this exact function on both an Integer stream and a Long stream:
List<Integer> intList = Arrays.asList(1, 2, 3); List<String> intResults = intList.stream().map(numberToString).collect(Collectors.toList()); List<Long> longList = Arrays.asList(1L, 2L, 3L); List<String> longResults = longList.stream().map(numberToString).collect(Collectors.toList());
If map() required Function<Integer, ?>, you couldn't reuse numberToString for the Integer stream—you'd have to write a duplicate function specifically for Integer.
Scenario 2: Method references to broader-type methods
Another common case is using method references that accept a parent type. For example:
// A utility method that works with any Object (parent of all Java types) public static String safeToString(Object obj) { return obj == null ? "[null]" : obj.toString(); } // You can pass this method reference directly to an Integer stream List<String> stringList = intList.stream().map(YourClass::safeToString).collect(Collectors.toList());
This works because Object qualifies as ? super Integer, making the method reference compatible with map()'s parameter.
Summary
The ? super P_OUT wildcard in Stream.map()'s Function parameter is all about flexibility and reusability. It lets you leverage any function that can handle the stream's element type or its ancestors, not just functions tied exactly to the element type. This design aligns with Java's generics philosophy: maximizing code reuse while keeping type checks strict.
内容的提问来源于stack exchange,提问作者Manikandan Kbk DIP

