【发布时间】:2019-07-12 07:45:50
【问题描述】:
我依稀记得在大学里学习,方法的返回类型应该总是尽可能窄,但我在网上搜索任何参考资料都是空的,SonarQube 称之为代码异味。例如。在下面的例子中(注意TreeSet和Set只是例子)
public interface NumberGetter {
Number get();
Set<Number> getAll();
}
public class IntegerGetter implements NumberGetter {
@Override
public Integer get() {
return 1;
}
@Override
public TreeSet<Number> getAll() {
return new TreeSet<>(Collections.singleton(1));
}
}
SonarQube 告诉我
声明应该使用诸如“List”之类的Java集合接口,而不是诸如“LinkedList”之类的具体实现类。 Java Collections API 的目的是提供定义良好的接口层次结构,以隐藏实现细节。 (鱿鱼:S1319)
我明白了隐藏实现细节的意义,因为我不能轻易地改变 IntegerGetter::getAll() 的返回类型而不破坏向后兼容性。但是通过这样做,我还为消费者提供了潜在的有价值的信息,即他们可以更改他们的算法以更适合使用TreeSet。如果他们不关心这个属性,他们仍然可以使用IntegerGetter(不管他们如何获得它),就像这样:
Set<Number> allNumbers = integerGetter.getAll();
所以我有以下问题:
- IntegerGetter::get() 返回更窄的类型是否合适?
- IntegerGetter::getAll() 返回更窄的类型是否合适?
- 是否有关于此主题的最佳实践,或者答案只是“取决于”?
(如果我用例如SortedSet 替换TreeSet,NB SonarQube 不会抱怨。这段代码的气味是否只是关于不使用 Collection API 接口?如果我的特定问题只有一个具体的类怎么办?)
【问题讨论】:
-
如果他们想使用专门的算法,他们可以使用
instanceof。一般来说,SonarQube 推荐正确的最佳做法:尽可能始终使用适当的收集界面。 -
这真的是一个判断电话。有一个论点是您应该对接口进行编码,因此返回 Set 意味着您可以稍后进行更改并且不会搞砸。另一方面,如果您正在使用 getter 并且需要继续使用 TreeSet,那么这确实是您界面的一部分。如果你只在调用 getter 后执行 Set 方法,那么返回 Set 是安全的。如果你有理由,你总是可以让它更具体。
标签: java generics collections covariance