【发布时间】:2013-01-30 07:04:08
【问题描述】:
我正在构建一个每天处理中等数据量的 Java 后端组件。我们有一个 POJO,我们称之为Widget,它上面有大约 10 个属性。我的软件必须处理Widget 列表组:本质上还有其他进程(完全不同的系统)将它们自己的List<Widget> 组合在一起,然后将它们发送到我的软件。我的软件实际上收到了一个如下所示的包装 POJO:
public class Payload {
private List<Widget> widgets; // <-- what I want
private String guid; // GUID; my software doesn't need this
private boolean fizz; // again, my software doesn't need this
... many other properties that I don't care about
}
我的软件聚合了所有这些List<Widget>,每个都由不同的系统创建,然后将它们一起大批量处理。
我暂时选择了ArrayList<ArrayList<Widget>>作为保存这批Widget列表的数据结构。 List<Widget>(外层ArrayList)大约有500,000组,每个List<Widget>每组大约有5个Widgets;在内部 ArrayList 中总共有大约 250 万 Widgets。
在最近的一次代码审查中,一些技术主管告诉我,我为这批 o' 小部件选择了错误的数据结构。他们告诉我我应该使用HashMap<String,List<Widget>>,因为它更高效且更易于使用。 hashmap 键是我的软件提供的Payload 中包含的 GUID。并不是说我出于任何原因都需要 GUID,它只是作为将 ~500,000 List<Widget> 分开的关键——我确实需要这样做。
这让我思考:谁是对的?!?我们对这个数据结构所做的唯一操作是“添加”(在ArrayList 的情况下,只需通过add(...) 添加Widget 或List<Widget>)然后“读取”(在我的软件中,我必须遍历每个 Widget 并检查它的内容。使用我的嵌套 ArrayList 它的要点是:
for(List<Widget> widgetList : myDoublyNestedArrayOfWidgets) {
for(Widget widget : widgetList) {
...
}
}
这些是我们唯一需要的操作:将不同的List<Widget>s 添加到一些大的“批处理”数据结构中,然后在稍后检查所有这些并处理每个Widget。该软件在一些具有大量内存和处理能力的增强型服务器上运行。
所以我问:**ArrayList<ArrayList<Widget>> 是正确的选择,HashMap<String,List<Widget>>,还是其他什么...为什么?
【问题讨论】:
-
我觉得你说了很多不需要回答核心问题的东西。尝试将其视为列出事实而不是讲述故事。
-
如果您一起处理所有内容,您是否可以使用
ArrayList<Widget>并在 Widget 进入时将它们添加到您的主列表中?此外,在开始处理之前您是否需要所有 500k 集,或者您是否可以处理每个进来的小列表并存储结果。生成一个线程来处理每个小列表,然后在完成后扔掉列表可能会提高内存效率 -
顺便说一句,你的用户名让我笑了 =)
-
处理顺序重要吗? IE。你想先处理旧批次吗?如果是这样,则 guid 键控 Map 会破坏此排序(除非您使用 TreeMap 并且可以保证 guid 是有序的)
-
@Dukeling 我部分同意,但是如果你跳到最后,问题就很清楚了。可能会从“TL;DR”标题中受益,但我发现额外的上下文对个人很有帮助。
标签: java performance list data-structures hashmap