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