在 Java 中列印堆疊值
1.概述
堆疊遵循後進先出(LIFO)規則;正確列印其值有時會很棘手。但別擔心,我們已經解決了!
在本教程中,我們將探索列印堆疊值的不同方法,從最簡單到最有效的方法。我們還將討論何時使用每種方法以及為什麼在現代 Java 開發中Deque
是Stack
的更好替代方案。
2. 使用Stack.toString()
如果我們只是需要快速查看我們的堆疊, toString()
方法就是我們最好的朋友。它內建於Stack
類別中(由於Vector
),因此它可以整齊地列印所有內容。
讓我們考慮一個堆疊。我們將在整個教程中使用這個範例:
Stack<Integer> stack = new Stack<>();
stack.push(10);
stack.push(20);
stack.push(30);
以下是Stack.toString()
的實作:
public static void givenStack_whenUsingToString_thenPrintStack() {
Stack<Integer> stack = new Stack<>();
stack.push(10);
stack.push(20);
stack.push(30);
System.out.println(stack.toString());
}
此方法的輸出將是:
[10, 20, 30]
這種方法非常適合快速調試和檢查堆疊的內容。由於它提供了直接而簡單的表示,因此當不需要考慮格式並且目標是一目了然地檢查堆疊的元素時,它效果最佳。
這種方法非常簡單,而且可以立即見效,非常適合快速調試。但是,它在輸出中包含方括號,這可能並不總是可取的。此外,由於輸出類似於列表,因此它沒有明確表明該結構是堆疊。
3. 使用增強型for
循環
如果我們必須以自訂格式列印元素,循環它們是一個很好的選擇。讓我們看看如何:
public static void givenStack_whenUsingForEach_thenPrintStack() {
Stack<Integer> stack = new Stack<>();
stack.push(10);
stack.push(20);
stack.push(30);
List<Integer> result = new ArrayList<>();
for (Integer value : stack) {
System.out.print(value + " ");
}
}
堆疊值將列印如下:
10 20 30
當需要更清晰或自訂的列印格式時,此方法是合適的。當元素的順序不是很重要時,它可以很好地工作,從而允許更好地控制堆疊內容的顯示方式。
4.使用forEach()
循環
我們可以使用 Java 8 forEach()
方法來取代傳統的 for-each 迴圈。但是,有一個重要的警告: Stack
或Deque
上的forEach()
方法不會按 LIFO 順序列印元素。它遵循集合的迭代順序,這意味著元素按照插入的順序列印。
以下是一個例子:
public static void givenStack_whenUsingDirectForEach_thenPrintStack() {
Stack<Integer> stack = new Stack<>();
stack.push(10);
stack.push(20);
stack.push(30);
stack.forEach(element -> System.out.println(element));
}
讓我們看一下輸出:
10
20
30
雖然這種方法可以完全控制格式,使其成為自訂輸出的理想選擇,但它不能保持 LIFO 順序,因為元素是按照插入順序而不是預期的堆疊順序列印的。我們需要像上面的程式碼一樣將其反轉,以便按後進先出的順序列印它。
如果我們需要按後進先出 (LIFO) 順序列印,我們應該先反轉堆疊,然後再呼叫forEach()
:
public static void givenStack_whenUsingStreamReverse_thenPrintStack() {
Stack<Integer> stack = new Stack<>();
stack.push(10);
stack.push(20);
stack.push(30);
stack.stream()
.sorted(Comparator.reverseOrder())
.forEach(System.out::println);
}
因此,我們的輸出看起來是這樣的:
30
20
10
這樣,我們就可以按照後進先出的順序來取得堆疊元素。
5.使用Iterator
Iterator
讓我們逐一遍歷每個元素:
public static void givenStack_whenUsingIterator_thenPrintStack() {
Stack<Integer> stack = new Stack<>();
stack.push(10);
stack.push(20);
stack.push(30);
Iterator<Integer> iterator = stack.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
}
因此,如果我們列印堆疊,我們將得到:
10 20 30
當需要比基本循環所能提供的更多的靈活性時,這種方法很實用。它對於可能涉及在迭代時刪除元素的操作很有幫助。但是,它仍然不會按照後進先出的順序列印元素,而這可能並不總是理想的。雖然它適用於任何資料類型,但它比簡單的循環增加了更多的複雜性。
6. 使用ListIterator
取得真正的 LIFO 順序
如果我們需要按照真正的堆疊順序(LIFO)列印元素,那麼ListIterator
是最好的選擇。讓我們看看它的實際效果:
public static void givenStack_whenUsingListIteratorReverseOrder_thenPrintStack() {
Stack<Integer> stack = new Stack<>();
stack.push(10);
stack.push(20);
stack.push(30);
ListIterator<Integer> iterator = stack.listIterator(stack.size());
while (iterator.hasPrevious()) {
System.out.print(iterator.previous() + " ");
}
}
列印的堆疊將遵循後進先出的順序:
30 20 10
當需要以正確的堆疊順序(LIFO)列印元素而不修改堆疊時,這種方法是理想的。當使用Stack
類別並避免刪除元素時它特別有用。雖然它確保了正確的順序,但它需要稍微多一點的程式碼,並且僅限於Stack
,這使得它與Deque
不相容。
7. 最佳性能選擇: Deque
如果我們經常使用堆疊,我們應該使用Deque
( ArrayDeque
) 而不是Stack
。它速度更快、更有效率,是現代 Java 的首選。
讓我們來看看:
public static void givenStack_whenUsingDeque_thenPrintStack() {
Deque<Integer> stack = new ArrayDeque<>();
stack.push(10);
stack.push(20);
stack.push(30);
stack.forEach(e -> System.out.print(e + " "));
}
堆疊值將按照後進先出的順序列印:
30 20 10
這種方法非常適合需要更有效率的堆疊實現的場景。由於Deque
效能優於Stack
,因此特別推薦用於高效能應用程式。與Stack
不同, Deque
自然地保持了 LIFO 順序,同時提供了改進的同時支援。也是現代Java程式設計中的首選。但是,採用這種方法需要從Stack
切換到Deque
,這可能需要重構現有程式碼。
8.基於用例的最佳方法
讓我們看看哪種方法適合哪種情況。
- 快速調試 –
toString()
- 對於自訂格式 -
forEach()
或 Java 8forEach()
- 對於
Stack
中的後進先出順序 -ListIterator
- 最佳效能
Deque
(優於Stack
)
所以,選擇權在我們手中。
9. 結論
在本文中,我們看到列印堆疊值不僅僅是顯示元素;這是為了了解在正確情況下採取正確的方法。如果我們只是需要快速瀏覽一下, toString()
就可以了。
當格式很重要時, forEach()
和Iterator
提供了靈活性,而ListIterator
則確保了真正的 LIFO 順序。而當我們需要確保更好的效能時, Deque
就是最好的選擇。因此,最佳選擇取決於我們需要列印堆疊的場景。
與往常一樣,本文中提供的程式碼可在 GitHub 上找到。