在Java中,我们具有以下功能:
public Collection<String> removeNulls(Collection<String> input) {
List<String> output = new ArrayList<>();
// ...
return output;
}
请注意,我没有以任何方式修改输入,因为我们花了很多时间来使用ImmutableList
List。更常见的是,我们尝试尽可能确保功能的不变性。但是,我在这里看到的一个陷阱是,我的所有方法经常都使用自己的实现Collection
。如果有人在使用我的库时使用LinkedList
或aSet
或a SortedSet
,O(1)
则只要在他们的列表上调用我的函数,诸如“ lookups are ”或“ list总是被排序”的假设就会中断:
Set<String> mySet = new SortedSet<>();
mySet.add(10);
mySet.add(9); // I know that my collection is now sorted
Collection<String> myFilteredSet = removeNulls(mySet); // It is no longer sorted
Set<String> mySet = Sets.newSortedSet(myFilteredSet); // Have to sort it again
在a的情况下LinkedList
,这变得更加微妙,如果我的函数返回a List
,那么我将继续使用该列表。它不会有任何编译时错误,我们也不会看到这个问题。在前一种情况下,问题至少是显而易见的,因为我仍然必须将返回的Collection(或List)转换为Set,而且我知道发生了什么。如果要进行某些繁重的处理(取决于LinkedList
所使用的处理程序),则以后才会出现此问题。理想的方式(尽管这并不意味着“推荐”)是:
public List<String> removeNulls(List<String> input) {
List<String> output = (List<String>)input.getClass().newInstance();
// ...
return output;
}
这样,我确保至少使用相同的类型实现。您认为该问题的解决方案是什么?
编辑
只是为了澄清一点,我实际上没有removeNulls方法,这不是我想要的。这个问题与现实生活中的问题无关,而是更多的“思考问题”。换句话说,我的问题是,鉴于您给了我一个集合,我必须返回另一个以某种方式派生自该集合且不修改输入的集合,如何确保我的输出集合遵守合同(或输入收集的具体实现)?
我猜想,您想要的是用操作修改Collection接口withoutNulls
,并相应地实现它,但是由于您不能“向现有集合类中添加新方法”,因此您很不走运。但是,因为你经常使用自己的集合实现,也许你可以扩展你的接口,并提供了一些方法,以定期集合类转换成你自己的。
像这样:
public interface BetterCollection<E> extends Collection<E> {
BetterCollection<E> withoutNulls();
}
public class BetterLinkedList<E> extends LinkedList<E> implements BetterCollection<E> {
public BetterLinkedList() {}
public BetterLinkedList(LinkedList<E> input) {
super(input);
}
@Override
public BetterCollection<E> withoutNulls() {
BetterCollection<E> result = new BetterLinkedList<E>();
...
return result;
}
}
我认为在C#中可以使用扩展方法,但是您在实现上受到一些限制(例如,您无法访问私有字段,并且不确定它们是否可以是虚拟的)。
Java的另一种解决方案是重载方法,使它们接受不同的集合类型,例如removeNulls(LinkedList<String>)
或removeNulls(SortedSet<String>)
,但显然也有其缺点。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句