英文:
In my implementation I want to have different return type of the method
问题
我有以下问题。我有以下接口:
public interface Parser {
public Map<String, List<String>> parse() throws IOException;
}
我有两个实现:
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;
}
}
}
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;
}
}
}
我想要做的是更改代码和TimeParser的返回类型,使其返回类型为Map<String, List<LocalTime>>
。我已经阅读到为了拥有不同的类型,我需要父类型的子类,但我不知道如何在我的情况下做到这一点。
附:我知道Map<String, List<String>> result = new HashMap<>((Map) map);
是不好的代码,但我还不知道如何正确地将Map<Object, Object>
转换为Map<String, List<String>>
。如果您有任何建议,我将很乐意听取:)。
附加附:我使用这两个实现是因为我相信它们做了相同的事情:解析日志和txt文件中的文本:
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类现在有几个字段,全部都是字符串。我希望它有2个LocalTime类型的字段。
英文:
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.
答案1
得分: 3
接受以下两种情况之一:
Map<String, List<String>>;
或者
Map<String, List<LocalTime>>;
您可以在此情况下使用泛型,您只需要使用:
<T> Map<String, List<T>> parse() throws IOException;
^
此外,您的代码可以是:
return lines.collect(Collectors.toMap(
string -> string.substring(0, 3),
string -> Arrays.asList(string.substring(4).split("_"))));
或者,如果您想要一个 LocalTime 的列表,您可以解析您的字符串并收集如下:
return lines.collect(Collectors.toMap(
string -> string.substring(0, 3),
string -> Arrays.stream(string.substring(4).split("_"))
.map(LocalTime::parse) // 或者您可以使用日期时间格式化程序
.collect(Collectors.toList())
通过使用这种解决方案,您不需要进行类型转换。
英文:
To accept either :
Map<String, List<String>>
or
Map<String, List<LocalTime>>
You can use generic in this case, all you need is to use :
<T> Map<String, List<T>> parse() throws IOException;
^
Also your code can be :
return lines.collect(Collectors.toMap(
string -> string.substring(0, 3),
string -> Arrays.asList(string.substring(4).split("_"))));
Or if you want a List of LocalTime, you can parse your String and collect as this:
return lines.collect(Collectors.toMap(
string -> string.substring(0, 3),
string -> Arrays.stream(string.substring(4).split("_"))
.map(LocalTime::parse) // or you can use a Date time formatter
.collect(Collectors.toList())
You don't need to cast with this solution.
答案2
得分: 2
我会将Map<String, List<String>>
放在一个新类中,并提供一个getter,让我们称其为MapAsString
。将其作为类层次结构的一部分,这样你就会有class MapAsString extends DataMap
。接下来,创建一个新类,它是DataMap
的子类,或许叫做MapAsLocalTime
,其中MapAsLocalTime extends DataMap
。
额外加分:将你的父类class DataMap
定义为抽象类,并提供一个单一的抽象方法,你必须实现这个方法。这个方法使用泛型来返回一个List<String, T>
。你可以有一个构造函数,接受一个T
(泛型类型),该类型在构造时定义。如果这看起来太难,或许只需使用通配符?
来返回任何类型... 因此getter返回List<String, ?>
- 这里的?
可以是任何类型的对象。
英文:
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
答案3
得分: 0
interface Parser<T> {
public Map<String, List<T>> parse() throws IOException;
}
class RacerInfoParser implements Parser<String> {
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<String, List<String>> map = lines.collect(Collectors.toMap(
string -> string.substring(0, 3),
string -> Arrays.asList(string.substring(4).split("_"))));
return map;
}
}
}
class TimeParser implements Parser<LocalTime> {
private final Path path;
public TimeParser(Path path) {
this.path = path;
}
@Override
public Map<String, List<LocalTime>> parse() throws IOException {
try (Stream<String> lines = Files.lines(path)){
Map<String, List<LocalTime>> result = lines.collect(Collectors.toMap(
string -> string.substring(0, 3),
string -> Arrays.stream(string.substring(4).split("_"))
.map(LocalTime::parse)
.collect(Collectors.toList())
));
return result;
}
}
}
英文:
You can use generics T. Like this way
interface Parser<T> {
public Map<String, List<T>> parse() throws IOException;
}
class RacerInfoParser implements Parser<String>{
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 <String, List<String>> map = lines.collect(Collectors.toMap(
string -> string.substring(0,3),
string -> Arrays.asList(string.substring(4).split("_"))));
return map;
}
}
}
class TimeParser implements Parser<LocalTime> {
private final Path path;
public TimeParser(Path path) {
this.path = path;
}
@Override
public Map <String, List<LocalTime>> parse() throws IOException {
try (Stream<String>lines = Files.lines(path)){
Map<String, List<LocalTime>> result = lines.collect(Collectors.toMap(
string -> string.substring(0,3),
string -> Arrays.stream(string.substring(4).split("_"))
.map(LocalTime::parse)
.collect(Collectors.toList())
));
return result;
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论