提问人:3rdRockSoftware 提问时间:9/1/2023 更新时间:9/3/2023 访问量:57
我可以嵌套多深的地图,有没有更好的方法
How deeply can I nest maps and is there a better way
问:
我正在创建具有此结构的 XML 文件
<test details>
<test name>test 1</test name
<test result>
<test date>2023-01-03</test date>
<test value>16</test value>
<test date>2023-01-02</test date>
<test value>18</test value>
<test date>2023-01-01</test date>
<test value>24</test value>
</test result>
<test name>test 2</test name>
<test result>
<test date>2023-01-03</test date>
<test value>16</test value>
<test date>2023-01-02</test date>
<test value>18</test value>
<test date>2023-01-01</test date>
<test value>24</test value>
</test result>
</test name>
</test details>
我的计划是使用地图来描述巢穴的每个深度。 我想我可以根据需要尽可能深入地嵌套地图,但迭代它们一定是一场噩梦。
这是我对创建XML所需的数据结构的思考
**test result** is a list of maps Map<date, value> results;
**test name** is a list of maps Map<key, Map of results> testNames;
**test details** is a list of maps Map<key, Map of test names> testDetails;
除了测试日期需要按时间降序排列外,地图不一定需要排序。也就是说,我目前的想法是使用 TreeMap 来保持整洁
我的问题是: 我是否需要一个嵌套的 for 循环 3 深度来迭代所有地图,是否有比 Map 更好的数据结构来实现所需的输出?
答:
我认为你有这个倒退 - 从对你的类进行建模开始,然后担心 xml 序列化 - 在你的情况下,你会想要这样的东西:
record Details(String name,List<Result> results) ;
record Result(LocalDate date,String value) ;
在 XML 中尽可能深入地嵌套元素是没有问题的,而且导航结构根本不是噩梦:如果你的数据结构是递归的,那么你通常希望使用递归代码来处理它(使用 XSLT 可以很容易地完成,XSLT 是一种专为这项工作设计的语言,但如果你愿意,你可以使用其他编程语言。
继 Answer by Kay 之后,更复杂的方法是定义自己的类来表示这些信息,而不是嵌套映射。
如果自定义类的目的是以透明且不可变的方式传输数据,则将类定义为记录。
层次结构的底部是一个结果,一个带有分数的日期。
public record Result( LocalDate date , int score ) { }
如果要对这些对象的集合进行排序,我们必须使类实现。Result
Comparable
public record Result( LocalDate date , int score ) implements Comparable < Result >
{
private static final Comparator < Result > comparator =
Comparator
.comparing ( Result :: date )
.thenComparing ( Result :: score );
@Override
public int compareTo ( Result o )
{
return Result.comparator.compare ( this , o );
}
}
我们为特定的命名测试收集这些结果。在 Java 21+ 中,使用 SequencedCollection
;在早期的 Java 中使用 .NavigableSet
public record Test( String name , SequencedCollection < Result > results ) { }
将这些对象作为类收集到一个集合中。如果除了测试集合之外没有其他字段,那么在 Java 中的层次结构中,我们实际上并不需要这个级别。但是在 XML 中,应该有一个外部元素来包装所有内容;此类与外部 XML 元素平行。Test
Detail
public record Detail( Collection < Test > tests ) { }
请注意,我删除了您的元素。这些元素在层次结构中创建了一个毫无意义的额外级别。<test result>
顺便说一句,我真的不喜欢这些名字和.第一个在 Java 开发中具有特定的含义。第二种通常用于讨论。因此,将它们用作类名和字段名可能会造成混淆。我建议设计更好、更有意义的名字。Test
Result
您的结果数据是相同的,因此我更改了它们以区分样本。
Test test1 =
new Test (
"test 1" ,
new TreeSet <> ( // Use `TreeSet` as it implements `SequencedCollection`.
Set.of (
new Result ( LocalDate.parse ( "2023-01-03" ) , 16 ) ,
new Result ( LocalDate.parse ( "2023-01-02" ) , 18 ) ,
new Result ( LocalDate.parse ( "2023-01-01" ) , 24 )
)
)
);
Test test2 =
new Test (
"test 2" ,
new TreeSet <> ( // Use `TreeSet` as it implements `SequencedCollection`.
Set.of (
new Result ( LocalDate.parse ( "2023-01-03" ) , 7 ) ,
new Result ( LocalDate.parse ( "2023-01-02" ) , 42 ) ,
new Result ( LocalDate.parse ( "2023-01-01" ) , 99 )
)
)
);
Detail detail =
new Detail (
List.of (
test1 ,
test2
)
);
System.out.println ( "detail = " + detail );
运行时:
detail = Detail[tests=[test[name=test 1, result=[Result[date=2023-01-01, score=24], Result[date=2023-01-02, score=18], Result[date=2023-01-03, score=16]]], Test[name=test 2, result=[Result[date=2023-01-01, score=99], Result[date=2023-01-02, score=42], Result[date=2023-01-03, score=7]]]]]
如果通过 Jakarta XML Binding 4.0 或更早版本解析/生成 XML,则需要将这些类转换为常规类。Jakarta EE Platform 11 的下一个版本将支持记录,因此我预计 Jakarta XML Binding 届时也会支持。record
评论
Map<String, Map<Date, Integer>>
String
Integer
Collection
<test result>