In a course on Spring Batch, I was surprised to see ? extends String.
Since String is a final class, how is this correct?
public void write(List<? extends String> items) throws Exception {
System.out.println(String.format("Received list of size: %s", items.size()));
items.forEach(System.out::println);
}
CodePudding user response:
Technically you are correct, in this case only a String would work because String is final. Still best to always follow PECS. A more practical example would probably use ? extends CharSequence. For example,
public static void write(List<? extends CharSequence> items) {
System.out.println(String.format("Received list of size: %s", items.size()));
items.forEach(System.out::println);
}
Now you can call it with any kind of CharSequence.
public static void main(String[] args) {
write(List.of(new StringBuilder("Hello"), new StringBuilder("World")));
write(List.of("Hello", "World"));
}
CodePudding user response:
You're correct that there will never be another class that extends String. So the only type that can fill that ? is String itself. However, the extends / super still conveys intent. Namely, a List<? extends String> is a read-only list. You can't add elements to it since ? extends String is a producer. A List<String> is potentially a read-write collection. So by writing List<? extends String>, we're conveying to whoever is reading the code (and to the compiler) that we only intend to read values from this List, not write anything back.
CodePudding user response:
? extends String is a generics qualifier. What it means in this particular case is that the method expects a List of elements which are compatible with String. There is nothing wrong with this definition - in fact, I would even consider it slightly more accurate and universal than List<String>.
But you're right, since there will never be another String, this is equivalent to List<String> for all practical purposes.
