比双重嵌套的ArrayList更有效?

时间:2013-02-14 13:03:57

标签: java performance list data-structures hashmap

我正在构建一个每天处理大量数据的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>列表的数据结构。将有大约500,000个ArrayList组(外部List<Widget>),每个Widget各有约Widget个;内部ArrayList的总计约250万HashMap<String,List<Widget>> s。

在最近的一次代码审查中,一些技术主管告诉我,我为这批次的小部件选择了错误的数据结构。他们告诉我,我应该使用Payload,因为它更有效,更容易使用。 hashmap键是我的软件给出的List<Widget>中包含的GUID。并不是因为任何原因我需要GUID,它只是保持~500,000 ArrayList分开的关键 - 我需要这样做。

这让我想到:谁是对的?!?我们在此数据结构上执行的唯一操作是“添加”(在Widget的情况下,只需通过List<Widget>添加add(...)Widget)然后“读取”(在我的软件中,我必须遍历每个ArrayList并检查它是否有东西。我的嵌套for(List<Widget> widgetList : myDoublyNestedArrayOfWidgets) { for(Widget widget : widgetList) { ... } } 的要点是:

List<Widget>

这些是我们需要的唯一操作:将不同的Widget添加到某个大型“批处理”数据结构中,然后在以后检查所有这些操作并对每个ArrayList<ArrayList<Widget>>执行操作。该软件运行在一些具有大量内存和处理能力的强化服务器上​​。

所以我问:** HashMap<String,List<Widget>>是正确的选择,{{1}}还是别的......为什么?

6 个答案:

答案 0 :(得分:3)

  

所以我问:ArrayList<ArrayList<Widget>>是正确的选择,HashMap<String,List<Widget>>还是别的......为什么?

最后,重要的是你的软件解决了它应该解决的问题。

HashMap比ArrayList更昂贵,如果您不需要通过密钥访问数据,则ArrayList可能是最佳选择。 此外,使用ArrayList时,编写执行处理所需的代码似乎更简单有效。

顺便说一句,让ArrayList<ArrayList<Widget>>HashMap<String,List<Widget>>闻起来有点气味。也许您正在建模的是ArrayList<WidgetGroup>WidgetGroup包含List<Widget>(所有其他属性 - 当下 - 您可能不需要)。但是,如果您的WidgetGroup只包含一个ArrayList,请不要引入这个新类(保持简单)。

  

这让我想到:谁是对的?!?

在你的解决方案和同行评审员之间,我个人非常喜欢你的。

但是,你可以为自己保留这个并遵循“技术主管”。如果这是他们的角色,那么他们的决定很重要,他们有责任提供这些选择。 (支付支票的人总是对的)

答案 1 :(得分:2)

您使用的是名词,但数据模型中缺少该名词:批次。 如果您真的关心将它们保留在批次中并保持代码可读,那么将它们封装在Batch类中:

class Batch {
    String guid;
    List<Widget> widgets;
}

而且,如果您不关心批次,那么您可以将它们全部压缩成一个List<Widget>吗?

答案 2 :(得分:1)

哈希映射不比数组列表更有效或更易于使用。如果在某些时候您确实需要通过其GUID键查找批次,则可以证明更改是合理的。

哈希映射的效率低于数组列表,因为调整大小意味着必须重新评估哈希码并将数据重新分配到相当随机的内存位置。另一方面,调整数组大小会将旧数组中的内容线性复制到新数组,这对CPU缓存来说更为友好。

哈希映射也不容易使用。要访问这些条目,您必须浏览地图的条目集,这会打破law of Demeter

答案 3 :(得分:0)

也许嵌入式(核心内)数据库是您最终想要的。另一种可能性是JavaSpaces / NoSQL,解耦传递和处理。取决于。

答案 4 :(得分:0)

从你的问题来看,很明显你正在做这些事情。

  1. 从您的数据中读取。
  2. 添加更多小部件。
  3. 问题是如何从ArrayList<ArrayList<Widget>> to HashMap<String,List<Widget>>改变您的数据结构影响上述两项活动。

    1)阅读:您已将它们分为4组,因此使用hashmap您将使用散列来存储您的组,这对于少量数据(组)实际上没有意义在你的情况下)所以不需要在这里使用hashmap。

    2)添加更多小部件:您将访问要添加的列表,因此您再次阅读相同内容。使用ArrayListObj.get(index)会没有坏处。

    现在使用ArrayList将始终按顺序阅读widgets。使用Hashmap无法完成哪些操作,但无论如何我不认为这是您关注的问题,还是它? : - )

答案 5 :(得分:0)

如果你必须随机访问内部列表,那么Hashmap会更有效率,而使用hashmap 的代码看起来对于在看到嵌套循环时在hives中突破的审阅者更为优雅。但是,如果你必须遍历并访问每个节点,你将不会比On ^ 2做得更好。你可以将它们填充到数据库中,但除了复杂性之外,它不会获得任何东西。它更优雅,就像hashmap一样。当然,所有这些都假设您拥有可以同时容纳所有250万个小部件的内存。如果你必须对它进行分页,那么某种DB SQL或NoSQL可能会更好。