I’m interested to write a generic split method, that can be invokes like this:
List<String> names = splitField("John, Nate, Larry", String::valueOf); List<Integer> ages = splitField("35, 23, 48", Integer::valueOf);
Here is my implementation:
private <T, R> List<R> splitField(String stringWithComma, Function<T, R> valueOf) { List<R> elements = new ArrayList<>(); if (stringWithComma != null && !stringWithComma.isEmpty()) { elements = Arrays.stream(stringWithComma.split(",")) .map(valueOf) .collect(Collectors.toList()); } return elements; }
It doesn’t build, What am I missing here?
Thanks!
EDIT 1:
This implementation builds and works well went invoked with String::valueOf
, but throws exception when invoked on Integer::valueOf
private <R> List<R> splitField(String elementsWithComma, Function<String, R> valueOf) { List<R> elements = new ArrayList<>(); if (elementsWithComma != null && !elementsWithComma.isEmpty()) { elements = Arrays.stream(elementsWithComma.split(",")) .map(valueOf) .collect(Collectors.toList()); } return elements; }
Advertisement
Answer
You are declaring a type parameter T
where you actually want String
, as the function is supposed to process a value you know to be a String
to R
. Remove the type parameter T
and change the function to Function<String, R>
.
private <R> List<R> splitField(String stringWithComma, Function<String, R> valueOf) { List<R> elements = new ArrayList<>(); if (stringWithComma != null && !stringWithComma.isEmpty()) { elements = Arrays.stream(stringWithComma.split(",\s*")) .map(valueOf) .collect(Collectors.toList()); } return elements; }
Note that I also change the split pattern to let it consume the space after commas, to avoid parse exceptions.
Following the PECS rule, you can relax the function signature, to support more use cases.
private <R> List<R> splitField( String stringWithComma, Function<? super String, ? extends R> valueOf) { List<R> elements = new ArrayList<>(); if (stringWithComma != null && !stringWithComma.isEmpty()) { elements = Arrays.stream(stringWithComma.split(",\s*")) .map(valueOf) .collect(Collectors.toList()); } return elements; }