背景:
Queue と Stack コレクションは、それぞれ FIFO (First-In-First-Out) と LIFO (Last-In-First-Out) の原則を実装する基本的なデータ構造です。これらは VB6 時代から活用されており、VB.NET の登場以降、これらの構造は標準クラスとなりました。Queue は要素が到着順に処理される必要があるシナリオ(例えば、タスクのキュー)に便利で、Stack は最後に追加された要素を他の要素よりも先に処理する必要がある場合(例えば、コールスタックやアクションの取り消し)に使用されます。
問題:
特定のタスクに対して適切でない構造を誤って選択したり、マルチスレッドシナリオで安全でない方法で使用したりすることがよくあります。また、空のスタックやキューから要素を抽出する際にエラーが発生し、例外を引き起こすこともあります。
解決策:
Visual Basic では、これらの構造を扱うために対応するクラスがあります:
System.Collections.QueueSystem.Collections.Stackキューとスタックの例:
' キューの操作 Dim q As New Queue() q.Enqueue("最初") q.Enqueue("二番目") Dim item = q.Dequeue() ' item = "最初" ' スタックの操作 Dim s As New Stack() s.Push("A") s.Push("B") Dim top = s.Pop() ' top = "B"
主な特徴:
1. For Each を使用してイテレーション中に Queue または Stack コレクションを変更できますか?
いいえ、For Each を使用してコレクションを繰り返し処理中に要素を追加または削除すると、InvalidOperationException が発生します。
コード例:
Dim q As New Queue() q.Enqueue(1) q.Enqueue(2) For Each elem In q q.Enqueue(3) ' イテレーション中に例外が発生します Next
2. 空の Queue または Stack の場合、Peek() メソッドは何を返しますか?
Peek はコレクションが空の場合、デフォルト値を返すのではなく、InvalidOperationException をスローします。
コード例:
Dim st As New Stack() Dim first As Object = st.Peek() ' 例外!
3. Queue(Of T) の Queue との違いは何ですか、またなぜジェネリックコレクションを優先するべきですか?
Queue(Of T) は Queue のジェネリックバージョンで、型安全であり、ボクシング/アンボクシングを回避できます。既知の型を使用する際は常にこれを選択する方が良いです。
Dim numbers As New Queue(Of Integer)() numbers.Enqueue(5) ' 整数のみ
ドキュメント印刷のキューが実装されたアプリケーションで、開発者は印刷ジョブを Stack に保存し、Queue ではなく Stack に保存しています。その結果、ドキュメントは逆順で印刷されます(最後に追加されたものが最初に処理されます)。
利点:
欠点:
同じプロジェクトが印刷ジョブの保存に Stack の代わりに Queue を使用するように変更します。これで、ドキュメントは左から右に順番に印刷され、ユーザーの期待に沿った動作となります。
利点:
欠点: