我有一个方法,每次执行时都会生成一个对象,我需要颠倒获取它们的顺序。所以我认为最自然的做法是堆栈,因为它是 LIFO。
然而,Java Stack似乎不能很好地与新的 Java 8 流式 API 配合使用。
如果我这样做:
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 顺序将它们输出到流中? 这是以正确(LIFO)顺序将所有项目从堆栈中清除到列表中的正确方法吗?
最佳答案
正如评论中已经提到的,我们已经很好地测试了 Deque
应该首选的接口(interface)。
但是我会告诉你原因Stack
不应该使用。
首先是 Java Doc。堆栈的自己说:
A more complete and consistent set of LIFO stack operations is provided by the Deque interface and its implementations, which should be used in preference to this class. For example:
Deque<Integer> stack = new ArrayDeque<Integer>();
见 JavaDoc .
那么 Stack
类有什么问题。
就像 Martin Fowler 在他的书中已经提到的那样 重构:改进现有代码的设计 在重构方法Replace Inheritance with Delegation, Stack 不应该从 Vector 继承。
One of the classic examples of inappropriate inheritance is making a stack a subclass of vector. Java 1.1 does this in its utilities (naughty boys!) [6, p. 288]
相反,他们应该使用如下图所示的委托(delegate), 这也是书上的。
参见此处:Replace Inheritance with Delegation
那么,为什么这是个问题:
因为堆栈只有 5 个方法:
- 流行音乐
- 推
- 是空的
- 搜索
- 尺寸
size()
和 isEmpty()
继承自 Vector
Vector
中的类和其他方法不使用。但是通过继承,其他方法被转发到 Stack
类,这是没有意义的。
福勒对这个问题说:
You can live with the situation and use convention to say that although it is a subclass, it's using only part of the superclass function. But that results in code that says one thing when your intention is something else—a confusion you should remove.
这伤害了 Interface Segregation Principle
上面写着:
CLIENTS SHOULD NOT BE FORCED TO DEPEND UPON INTERFACES THAT THEY DO NOT USE.
您可以查看Vector的源代码和 Stack类(class)
你会看到 Stack 类继承了 spliterator
方法
和 Vector
类中的 VectorSpliterator
innerClass。
Collection
接口(interface)使用此方法来实现。流方法的默认版本:
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
因此,请避免简单地使用 Vector
和 Stack
类。
[6] 重构:改进现有代码的设计 Fowler,Martin 1997 年
关于java - 使用 Java 8 集合流 API 堆栈,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30387579/