我有一个方法,每次我执行它时都会生成一个对象,我需要颠倒获取它们的顺序。所以我认为最自然的方式应该是堆栈,因为它是后进先出的。
然而,Java似乎不能很好地与新的Java8流Stack配合使用。
如果我这样做:
Stack<String> stack = new Stack<String>();
stack.push("A");
stack.push("B");
stack.push("C");
List<String> list = stack.stream().collect(Collectors.toList());
System.out.println("Collected: " + list);我得到的输出是:
Collected: [A, B, C]为什么它没有按照预期的后进先出顺序将它们输出到流中?这是以正确的(LIFO)顺序将堆栈中的所有项刷新到列表中的正确方式吗?
发布于 2015-05-22 14:36:32
正如评论中已经提到的,我们已经对Deque接口进行了很好的测试,这应该是首选的。
但是我会给你一个不应该使用Stack的理由。
首先,Java文档。堆栈本身就说明了问题:
Deque接口及其实现提供了一组更完整和一致的后进先出堆栈操作,应该优先于此类使用。例如:
去队列堆栈=新的ArrayDeque();
参见JavaDoc。
那么Stack类的问题是什么呢?
就像Martin Fowler在他的书 refactoring : Improving the Design of Existing Code at the refactoring method Replace Inheritance with Delegation中提到的那样,栈不应该继承自。
是不适当继承的经典例子之一,它使堆栈成为vector的子类。Java1.1在它的实用程序中做到了这一点(淘气的男孩!) 6,第288页
相反,他们应该像下面的图片一样使用委托,这也是本书中的内容。
另请参阅此处:Replace Inheritance with Delegation

那么,为什么这是一个问题:
因为堆栈只有5个方法:
size()和isEmpty()是从Vector类继承的,不使用来自Vector的其他方法。但是通过继承,其他方法被转发到Stack类,这是没有意义的。
福勒对这个问题说:
你可以接受这种情况,并使用约定来说明,虽然它是一个子类,但它只使用了超类函数的一部分。
。但这会导致代码在你的意图是其他东西时说明一件事--这是你应该消除的困惑。
这会伤害Interface Segregation Principle
上面写着:
不应强制
客户端依赖于它们不使用的接口。
Stack您可以查看Vector和Stack类的源代码Stack,您将看到Stack类从Vector类继承了spliterator方法和VectorSpliterator innerClass。
Collection接口使用此方法来实现。stream方法的默认版本:
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}因此,避免简单地使用Vector和Stack类。
6重构:改进现有代码的设计Fowler,Martin,1997年
https://stackoverflow.com/questions/30387579
复制相似问题