用Java返回集合的最佳方法是什么?
我应该允许调用者提供要添加的集合吗?或者只返回List<>
或Set<>
项?或两者兼而有之?
public class Item { ... }
public class SomeOtherClass
{
private List<Item> myItems;
public List<Item> getItems()
{
return Collections.unmodifiableList(this.myItems);
}
public void collectItems(Collection<? super Item> target)
{
target.addAll(myItems);
}
}
注意:以上示例假设已存在可立即返回的列表。当这样的列表以前不存在时,我也对适当的答案感兴趣,并且必须在调用者调用getItems()或collectItems()时生成。 (我根据Mykola提出的观点重命名了collectItems。)
答案 0 :(得分:12)
通过return
返回结果更好(除非一些性能问题)。通过这种方式,可以更清楚地了解发生了什么。
如果您选择第二个选项(填充客户端的集合),那么最好将函数从getItems
重命名为fillWithItems
以避免模糊代码。
另外,不要忘记JavaBeans及其约定。
答案 1 :(得分:6)
我更喜欢List<Item> getItems()
方法。 void getItems(Collection<? super Item> target)
对调用者仅仅执行myCollection.addAll(foo.getItems())
性能或其他方式没有任何实际优势。 Collections.unmodifiableXYZ
只创建一个包装器,而不是集合的完整副本,因此如果立即使用包装器并将其丢弃,它将永远不会从第一代开始,并且将以很少的开销快速收集。
如果并不总是实现项目集合,那么当您不知道有多少项目时,您可能会考虑让getItems返回Iterable<Item>
。如果您知道项目数并且可以为它们编写迭代器,那么编写AbstractCollection
的自定义子类并返回它就很容易了。
答案 2 :(得分:0)
你应该归还一个集合。 Java中比使用输入/输出参数更常见的方法。我认为没有任何理由会因返回大型集合而导致性能下降,而且代码会更清晰。
答案 3 :(得分:0)
考虑到Java的工作方式,您通常会期望返回版本。
但是,如果您需要控制创建的集合类型,那么您将执行将其作为参数传递的版本。
通常什么都不应该关心创建什么类型的集合,因此通常应该使用返回版本。顺便说一下,好好利用了unmodifiableList。
答案 4 :(得分:0)
注意:返回一个Set并返回一个List会产生不同的含义。
套装没有重复且没有订单。向集合添加元素可能会导致元素的顺序不同。
列表可能包含重复项,添加元素不会(通常)更改列表的整体顺序。
至于如何返回列表,我会使用第一种形式:
public List<Item> getItems()
{
return Collections.unmodifiableList(this.myItems);
}
我无法想到后一种形式会带来任何好处的情况。 List不像是可以预先分配空间的数组。因此,通过传入List没有性能节省。
答案 5 :(得分:0)
我可以想到填充现有集合而不是创建新集合的唯一原因是当您遇到集合中对象类型的问题时。像Java库toArray(Object [] a)函数一样,程序在编译时不知道数组元素的适当类型是什么,所以它不能只返回,例如,一个String []。因此,他们将调用者传递给具有适当类型元素的数组,并填充它。
90%的时间您确切地知道要返回的对象类型,因此您可以这样做。
答案 6 :(得分:0)
您可以更改签名以返回Collection或Iterable。对于返回Iterable,你可以直接返回一个新的东西-Iterable(myItems.iterator())而不是myItems,以避免客户端可能试图强制转换为List(并修改它)。如果您不希望它们修改List,也可以考虑返回Iterator,但请注意Iterable更好,因为您可以直接在for-each循环中使用它们。
返回Iterable既可以明确你的意图,也可以在上面的例子中禁止修改。唯一的含义是您丢失了随机访问权限,这可能会也可能不是您需要的问题。