I have the following problem. I have the interface:
public interface Parser {
public Map<String, List<String>> parse() throws IOException;
}
I have two implementations:
public class RacerInfoParser implements Parser{
private final Path path;
public RacerInfoParser(Path path) {
this.path = path;
}
@Override
public Map <String, List<String>> parse() throws IOException {
try (Stream<String>lines = Files.lines(path)){
Map <Object, Object> map = lines.collect(Collectors.toMap(
string -> string.substring(0,3),
string -> Arrays.asList(string.substring(4).split("_"))));
Map<String, List<String>> result = new HashMap<>((Map) map);
return result;
}
}
}
and
public class TimeParser implements Parser {
private final Path path;
public TimeParser(Path path) {
this.path = path;
}
@Override
public Map <String, List<String>> parse() throws IOException {
try (Stream<String>lines = Files.lines(path)){
Map <Object, Object> map = lines.collect(Collectors.toMap(
string -> string.substring(0,3),
string -> Arrays.asList(string.substring(3).split("_"))));
Map<String, List<String>> result = new HashMap<>((Map) map);
return result;
}
}
}
What I want to do is to change the code and the return type of TimeParser so that it returns the result of type Map<String, List <LocalTime>. I have read that in order to have a different type I need to have a sub-class of the parent type, but I don’t understand how to do it in my case.
P.S. I know that Map<String, List<String>> result = new HashMap<>((Map) map); is a bad code, but I don’t know yet how to properly convert Map<Object, Object to Map<String, List<String>>. If you have any suggestions I will be glad to listen to them:).
P.S.S. I use these two implementations because I beleive they do the same thing: parse text from log and txt files:
public class RacerBuilder {
public List<Racer> buildRacers () throws URISyntaxException, IOException {
Parser racerInfoParser = new RacerInfoParser(Paths.get(getClass().getClassLoader()
.getResource("abbreviations.txt").toURI()));
Parser startTimeParser = new TimeParser(Paths.get(getClass().getClassLoader()
.getResource("start.log").toURI()));
Parser endTimeParser = new TimeParser(Paths.get(getClass().getClassLoader()
.getResource("end.log").toURI()));
Map<String, List<String>> racerInfoMap = racerInfoParser.parse();
Map<String, List<String>> startTimeMap = startTimeParser.parse();
Map<String, List<String>> endTimeMap = endTimeParser.parse();
return racerInfoMap.keySet().stream()
.map(i -> new Racer (i,
racerInfoMap.get(i).get(0),
racerInfoMap.get(i).get(1),
startTimeMap.get(i).get(1),
endTimeMap.get(i).get(1),
endTimeMap.get(i).get(0)))
.collect(Collectors.toList());
}
}
Racer class now has several fields, all of them are Strings. I want it to have 2 fields of type LocalTime.
Advertisement
Answer
I’d wrap the Map<String, List<String>> in a new class with a getter, let’s call it MapAsString. Make it part of a class hierarchy so you have class MapAsString extends DataMap. Next have a new class that is a subclass of DataMap called perhaps MapAsLocalTime where MapAsLocalTime extends DataMap.
Bonus points: make your parent class DataMap abstract and provide a single abstract method you must implement. that uses Generics to return a List<String, T>. You can have a constructor that takes a T (generic type) which defines what type T will be at construction time. If this seems too hard, perhaps just have it return anything using the wildcard ?… so getter returns List<String, ?> – here ? can an object of any type