Stack using the Java 8 集合流 API
Stack using the Java 8 collection streaming API
我有一个每次执行都会生成一个对象的方法,我需要颠倒获取它们的顺序。所以我认为最自然的做法是堆叠,因为它是后进先出法。
但是,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]
为什么不按预期的后进先出顺序将它们输出到流中?
这是以正确的(后进先出)顺序将堆栈中的所有项目冲出到列表中的正确方法吗?
如评论中所述,我们已经很好地测试了Deque
接口,应该是首选。
但是我会告诉你不应该使用 Stack
的原因。
首先,Java 文档。堆栈的自述:
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
class.
有什么问题
就像 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]
相反,他们应该像下图那样使用委托,
也出自书本
另见此处:Replace Inheritance with Delegation
那么,为什么这是个问题:
因为Stack只有5个方法:
- 流行
- 推送
- 为空
- 搜索
- 尺寸
size()
和isEmpty()
是继承自Vector
class and the other methods from the Vector
没有使用。但是通过继承,其他的方法都转发给了Stack
class,这就没有意义了。
福勒对这个问题说:
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 and Stackclass的源代码
你会看到 Stack class 继承了 spliterator
方法
VectorSpliterator
innerClass 来自 Vector
class.
这个方法被Collection
接口用来实现。流方法的默认版本:
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
因此,请避免简单地使用 Vector
和 Stack
class。
[6] 重构:改进现有代码的设计 Fowler,Martin 1997 年
我有一个每次执行都会生成一个对象的方法,我需要颠倒获取它们的顺序。所以我认为最自然的做法是堆叠,因为它是后进先出法。
但是,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]
为什么不按预期的后进先出顺序将它们输出到流中? 这是以正确的(后进先出)顺序将堆栈中的所有项目冲出到列表中的正确方法吗?
如评论中所述,我们已经很好地测试了Deque
接口,应该是首选。
但是我会告诉你不应该使用 Stack
的原因。
首先,Java 文档。堆栈的自述:
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
class.
就像 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]
相反,他们应该像下图那样使用委托, 也出自书本
另见此处:Replace Inheritance with Delegation
那么,为什么这是个问题:
因为Stack只有5个方法:
- 流行
- 推送
- 为空
- 搜索
- 尺寸
size()
和isEmpty()
是继承自Vector
class and the other methods from the Vector
没有使用。但是通过继承,其他的方法都转发给了Stack
class,这就没有意义了。
福勒对这个问题说:
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 and Stackclass的源代码
你会看到 Stack class 继承了 spliterator
方法
VectorSpliterator
innerClass 来自 Vector
class.
这个方法被Collection
接口用来实现。流方法的默认版本:
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
因此,请避免简单地使用 Vector
和 Stack
class。
[6] 重构:改进现有代码的设计 Fowler,Martin 1997 年