web-dev-qa-db-ja.com

Java 8コレクションストリーミングAPIを使用してスタックする

オブジェクトを実行するたびにオブジェクトを生成するメソッドがあり、取得する順序を逆にする必要があります。だから私はそれが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)の順序でリストにフラッシュする正しい方法ですか?

20
jbx

すでにコメントで述べられているように、私達は Deque インターフェースを十分にテストしました。

しかし、 Stack を使用しない理由を説明します。

最初に、Java Doc。of the Stackは次のように述べています。

より完全で一貫性のあるLIFOスタック操作のセットは、Dequeインターフェースとその実装によって提供され、このクラスよりも優先して使用する必要があります。次に例を示します。

Dequeスタック=新しいArrayDeque();

JavaDoc を参照してください。

それで、Stackクラスの問題は何ですか。

Martin Fowlerが彼の本ですでに述べたようにRefactoring:Improving the Design of Existing Codeat the refactoring method 継承を委任で置き換える、スタックはベクターから継承しないでください。

不適切な継承の典型的な例の1つは、スタックをベクターのサブクラスにすることです。 Java 1.1はユーティリティでこれを実行します(いたずらな男の子!)[6、p。288]

代わりに、下の図のように本からの委任を使用する必要がありました。

ここも参照してください: 継承を委任に置き換える

Replace Inheritance with Delegation

では、なぜこれが問題なのでしょうか。

スタックには5つのメソッドしかないため:

  1. ポップ
  2. 押す
  3. isEmpty
  4. 探す
  5. サイズ

    size()およびisEmpty()Vector クラスから継承され、 Vector からの他のメソッドは使用されません。しかし、継承によって、他のメソッドはStackクラスに転送されますが、これは意味がありません。

そしてファウラーはこの問題にこう言っています:

この状況に対処し、規則を使用して、サブクラスであるにもかかわらず、スーパークラス関数の一部のみを使用していると言うことができます。しかし、その結果、意図が他の何かであるときに1つのことを言うコード、つまり、取り除かなければならない混乱が生じます。

これは インターフェース分離原理を傷つけます

それは言う:

クライアントは、使用しないインターフェースに依存することを強制されるべきではありません。


Vector および Stack クラスのソースコードをチェックアウトすると、Stackクラスがspliteratorを継承していることがわかりますメソッドとVectorSpliteratorクラスのVector innerClass。

このメソッドは、Collectionインターフェースが実装するために使用されます。ストリームメソッドのデフォルトバージョン:

default Stream<E> More ...stream() {
  return StreamSupport.stream(spliterator(), false);
}

したがって、VectorおよびStackクラスの使用は避けてください。

[6]リファクタリング:既存のコードファウラーのデザインの改善、1997年マーティン

32
Zelldon