4

我正在构建一个每天处理适量数据的 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>大约有5s Widget;内部总共有约 250 万WidgetArrayList

在最近的一次代码审查中,一些技术负责人告诉我,我为这批 o' 小部件选择了错误的数据结构。他们告诉我我应该使用HashMap<String,List<Widget>>,因为它更高效且更易于使用。hashmap 键是包含在Payload我的软件提供的 GUID 中。并不是说我出于任何原因都需要 GUID,它只是作为将 ~500,000List<Widget>分开的关键——我确实需要这样做。

这让我想:谁是对的?!?我们在这个数据结构上做的唯一操作是“添加”(在 的情况下ArrayList,只是添加一个Widget或一个List<Widget>via add(...))然后“读取”(在我的软件中,我必须遍历每一个Widget并检查它的东西。用我嵌套ArrayList的要点是:

for(List<Widget> widgetList : myDoublyNestedArrayOfWidgets) {
    for(Widget widget : widgetList) {
        ...
    }
}

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

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

4

6 回答 6

3

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

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

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

顺便说一句,有ArrayList<ArrayList<Widget>>,或HashMap<String,List<Widget>>闻到一点点。也许您正在建模的是 aArrayList<WidgetGroup>并且 aWidgetGroup包含 a List<Widget>(以及目前您可能不需要的所有其他属性)。但是,如果您的 WidgetGroup 只包含一个 ArrayList,请不要引入这个新类(使其更简单)。

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

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

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

于 2013-02-14T13:12:04.800 回答
2

有一个名词您一直在使用,但在您的数据模型中缺失:Batch。如果您真的关心将它们保存在批处理中并保持代码可读,那么将它们封装在 Batch 类中:

类批次{
    字符串向导;
    列出<Widget> 小部件;
}

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

于 2013-02-14T13:14:35.303 回答
1

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

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

哈希映射也不容易使用。要访问条目,您必须通过地图的条目集,这违反了得墨忒耳法则

于 2013-02-14T13:09:30.207 回答
0

也许嵌入式(核心)数据库是您最终想要的。另一种可能性是类似于 JavaSpaces/NoSQL,将交付和处理解耦。依靠。

于 2013-02-14T13:13:09.250 回答
0

从您的问题可以清楚地看出您正在做这些事情。

  1. 从您的数据中读取。
  2. 添加更多小部件。

问题出现了,改变您的数据结构将如何ArrayList<ArrayList<Widget>> to HashMap<String,List<Widget>>影响上述两个活动。

1)阅读:您已将它们分为 4 个组,因此使用hashmap您将使用散列存储您的组,这对于少量数据(在您的情况下为组)确实没有意义,因此无需在此处使用 hashmap。

2)添加更多小部件:您将访问要添加的列表,因此同样您可以阅读。使用不会有什么坏处 ArrayListObj.get(index)

现在使用ArrayList将始终widgets按顺序读取。哪个不会使用Hashmap,但无论如何我认为这不是你关心的问题,或者是吗?:-)

于 2013-02-14T13:14:44.250 回答
0

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

于 2013-02-14T13:18:26.407 回答