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.