由于以下代码行,我被Sonar拉了起来:
public void setFileNames(LinkedHashSet<String> fileNames) {
显示错误消息:
避免使用'LinkedHashSet'等实现类型;改为使用界面
当我想表示保持其插入顺序的非排序Set
时,有什么方法?我只是使用Set
并明确表示将保留迭代顺序吗?
存储的数据将使用JaxB序列化,反序列化后迭代顺序必不可少。
(我知道并完全理解this)
答案 0 :(得分:3)
没有这样的interface
,因为输入需要这种行为是没有意义的。代码创建 Set
可能有关于订单的意图,并在创建Set
时选择适当的实现。
但是,如果Set
是否具有插入顺序,字母顺序或任意,例如基于散列,顺序对像setFileNames(Set<String> fileNames)
?
将参数类型声明为Set
可以保证不存在对行为产生影响的重复项,但是插入顺序是无意义的信息(除非调用者使其有意义)关于Set
的历史。
如果您坚持使用方法签名setFileNames(LinkedHashSet<String> fileNames)
,我仍然可以通过无意义的顺序传递Set
,例如调用
setFileNames(new LinkedHashSet<String>(hashSet))
或具有字典顺序的集合,例如setFileNames(new LinkedHashSet<String>(treeSet))
。你的签名只会让它变得更复杂。
答案 1 :(得分:1)
我很欣赏其他答案,我也很欣赏声纳警告。但是,有时候(或许在您的情况下)可以忽略警告。在我看来,您正在使用LinkedHashSet
来精确定义调用者的职责。 Set不会传达您的要求(订单未保留)。也没有List(不保证不同的元素)。所以也许可以忽略这个警告。
另一种方法是你允许一个List,然后你必须仔细检查(在你的方法中)列表没有重复,如果存在则抛出异常。这对我来说似乎很荒谬。
正如其他人所说,你应该弄清楚如何抑制声纳中的警告。希望该机制能够包含您压制它的原因。然后你可以向未来的维护者解释你的决定。
答案 2 :(得分:1)
只需接受Set
,让调用者决定传入的实现。
保持其插入顺序?
这取决于来电者。 LinkedHashSet
会根据插入保留订单,TreeSet
会根据自然顺序保留订单。为什么你的方法要关心如何实现订单?
答案 3 :(得分:-1)
如果您需要订购要接收的元素,那么您的方法应该接收List而不是Set。但是为了摆脱警告,你必须使用Set而不是LinkedHashSet。在您的方法中使用接口而不是实际类是一种好习惯。您不应该公开接口的实际实现。
此外,如果你只需要迭代Set的元素,你就可以收到一个Iterator,并且只是迭代它。
编辑:如果你真的想确保你只收到一个LinkedHashSet,你可以这样做:
public void setFileNames(Set<String> fileNames) {
if (!(fileNames instanceof LinkedHashSet)) {
throw new IllegalArgumentException("I need a LinkedHashSet!");
}
}
编辑2:我不认为这里有一个理想的答案,但是如果你确实需要上面所有的东西都会收到一个LinkedHashSet,我会在界面中声明它并找到让Sonar忽略它的方法该警告的具体实例。