Java:List的ArrayList,Map的HashMap和Set的HashSet?

时间:2009-05-22 02:22:45

标签: java

我通常总是觉得使用标题中列出的接口的具体类就足够了。通常当我使用其他类型(例如LinkedList或TreeSet)时,原因是功能而不是性能 - 例如,队列的LinkedList。

我有时会构造一个初始容量超过默认值10的ArrayList和一个超过默认存储桶16的HashMap,但我通常(特别是对于商业CRUD)从未看到自己在想“嗯......我应该如果我要插入并迭代整个List,请使用LinkedList而不是ArrayList?“

我只是想知道这里的其他人使用什么(以及为什么)以及他们开发的应用程序类型。

10 个答案:

答案 0 :(得分:10)

这些肯定是我的默认值,虽然通常LinkedList实际上是列表的更好选择,因为绝大多数列表似乎只是按顺序迭代,或者通过Arrays.asList转换为数组。

但是在保持一致的可维护代码方面,标准化这些并使用替代方案是有道理的,当有人读取代码并看到替代方案时,他们立即开始认为代码正在做一些特殊的事情。

我总是将参数和变量键入为Collection,Map和List,除非我有特殊的理由引用子类型,这样切换就是需要时的一行代码。

如果你需要随机访问,我有时会看到明确要求一个ArrayList,但实际上这确实不会发生。

答案 1 :(得分:3)

对于某些类型的列表(例如听众),使用CopyOnWriteArrayList代替普通ArrayList是有意义的。对于几乎所有其他内容,您提到的基本实现都已足够。

答案 2 :(得分:2)

是的,我将它们用作默认值。我通常有一个规则,在公共类方法上,我总是返回接口类型(即Map,Set,List等),因为其他类(通常)不需要知道具体的具体类是什么。在类内部方法中,只有当我需要访问它可能具有的任何额外方法时(或者如果它更容易理解代码),我将使用具体类型,否则使用接口。

使用您使用的任何规则都非常灵活,但是,因为对具体类可见性的依赖会随着时间的推移而变化(特别是当您的代码变得更复杂时)。

答案 3 :(得分:2)

实际上,总是使用基本接口Collection,List,Map来代替它们的实现。为了使thinkgs更加灵活,您可以隐藏静态工厂方法背后的实现,这可以让您切换到不同的实现,以防您找到更好的东西(我怀疑这个领域会有很大的变化,但你永远不知道)。另一个好处是,由于泛型,语法更短。

Map<String, LongObjectClasName> map = CollectionUtils.newMap();

instead of 

Map<String, LongObjectClasName> map = new HashMap<String, LongObjectClasName>();


public class CollectionUtils {
.....

public <T> List<T> newList() {
        return new ArrayList<T>();
    }

    public <T> List<T> newList(int initialCapacity) {
        return new ArrayList<T>(initialCapacity);
    }

    public <T> List<T> newSynchronizedList() {
        return new Vector<T>();
    }

    public <T> List<T> newConcurrentList() {
        return new CopyOnWriteArrayList<T>();
    }

    public <T> List<T> newSynchronizedList(int initialCapacity) {
        return new Vector<T>(initialCapacity);
    }

...
}

答案 4 :(得分:1)

我真的没有“默认”,但我想我经常使用问题中列出的实现。我想到什么是适合我正在处理的任何特定问题,并使用它。我不是盲目地默认使用ArrayList,我按照“好吧,我将要进行大量迭代并删除此列表中间的元素的思路进行了30秒的思考。我应该使用LinkedList“。

我几乎总是使用接口类型作为参考,而不是实现。请记住,List不是LinkedList实现的唯一接口。我看到了很多:

LinkedList<Item> queue = new LinkedList<Item>();

当程序员意味着时:

Queue<Item> queue = new LinkedList<Item>();

我也使用了Iterable接口。

答案 5 :(得分:1)

如果您正在为队列使用LinkedList,则可以考虑使用Deque接口和ArrayDeque实现类(在Java 6中引入)。引用Javadoc for ArrayDeque:

  

这门课的速度可能比   堆叠用作堆栈时,速度更快   用作队列时的LinkedList。

答案 6 :(得分:1)

刚刚从类中了解了数据结构性能,在选择实现之前,我通常会看一下我正在开发的算法类型或结构的目的。

例如,如果我正在构建一个对其进行大量随机访问的列表,我将使用ArrayList,因为它的随机访问性能很好,但是如果我将很多内容插入到列表中,我可能会选择LinkedList。 (我知道现代实现消除了许多性能障碍,但这是我想到的第一个例子。)

您可能希望查看一些维基百科页面的数据结构(特别是那些处理性能特别重要的sorting algorithms页面)以获取有关性能的更多信息,以及有关Big O notation的文章关于衡量数据结构上各种功能的性能的一般性讨论。

答案 7 :(得分:0)

我倾向于使用其中一个* Queue类作为队列。但是,如果您不需要线程安全,LinkedList是一个不错的选择。

答案 8 :(得分:0)

使用接口类型(List, Map)而不是实现类型(ArrayList, HashMap)在方法中无关紧要 - 它在公共API中非常重要,即方法签名(和“公共”不一定意思是“打算在你的团队之外发布”。

当一个方法将ArrayList作为参数,并且您还有其他内容时,您就会被搞砸,并且必须毫无意义地复制数据。如果参数类型是List,则呼叫者更灵活,并且可以例如使用Collections.EMPTY_LISTCollections.singletonList()

答案 9 :(得分:0)

我也经常使用ArrayList,但我会根据具体情况使用TreeSet或HashSet。但是,在编写测试时,也经常使用Arrays.asList和Collections.singletonList。我主要编写线程本地代码,但我也可以看到使用各种并发类。

此外,有些时候我使用ArrayList时我真正想要的是LinkedHashSet(在它可用之前)。