Java
 Computer >> コンピューター >  >> プログラミング >> Java

JavaのStackクラス徹底解説!LIFO構造の基本と主要メソッドの使い方

Javaにおけるスタック(Stack)は、「後入れ先出し(LIFO: Last-In, First-Out)」と呼ばれるデータ構造です。スタックから最初に取り出されるのは、最後に追加された要素です。新しい要素は常にスタックの末尾に追加され、JavaのStackクラスはVectorクラスを継承しています。

Javaのスタックとは

プログラミングにおいて、スタックはデータを格納するための後入れ先出し(LIFO)のデータ構造です。リスト内の対称性を検証したり、リストの順序を逆転させたりするなど、さまざまな場面で活躍します。

Javaのコレクションフレームワークには、スタックを構築するためのStackクラスが用意されています。この記事では、Javaのスタックの基礎知識、スタックの作成方法、そしてStackクラスが提供する主要なメソッドについて、サンプルコードを交えながら詳しく解説します。

スタックの仕組み:Webブラウザの履歴を例に

Javaのスタックは、後入れ先出し(LIFO)構造で要素を格納します。つまり、スタックの一番上に追加された要素が、最初に取り出される要素になります。

身近な例として、Webブラウザのページ履歴機能が挙げられます。Webページにアクセスすると、ブラウザはそのページを閲覧履歴に記録します。この記録こそがスタックなのです。

新しいページにアクセスするたびに、ブラウザは閲覧スタックにエントリを追加していきます。「前のページに戻りたい」とき(last-in)、ブラウザはスタックから最新のエントリを先に取り除きます(first-out)。以下の表は、スタックの具体例です。

サイト名
google.com
nytimes.com
careerkarma.com

これが閲覧履歴のスタックです。現在はgoogle.comのトップページにおり、その前にニューヨーク・タイムズのトップページ、さらにその前にはCareer Karmaのトップページを見ていたことになります。

google.comはスタックの一番上にあります。戻るボタンを押して直前のページに戻るとき、ブラウザが最初にスタックから取り除くのがgoogle.comです。

もう一つの分かりやすい例が「本の積み重ね」です。山積みになった本を読むとき、上から順に取り出しますよね。最後に積んだ本が最初に手に取る本になる——これがまさにLIFOというわけです。

スタックを扱う際、リストの最後尾にある項目は「スタックのトップ(top)」と呼ばれます。先ほどの例で言えば、google.comが最も最近訪れたサイトなので、スタックのトップに位置しているのです。

Javaでスタックを作成する方法

Javaでスタックを作成するには、まずjava.util.Stackパッケージをインポートする必要があります。インポート方法は次の通りです。

import java.util.Stack;

パッケージをインポートしたら、次の構文でスタックを作成できます。

Stack<DataType> stack_name = new Stack<>();

各構成要素の意味は次の通りです。

  • Stack:スタックを宣言することをプログラムに伝えます。
  • DataType:スタックに格納するデータの型です。
  • stack_name:スタックにつける名前です。
  • new Stack<>();:新しいJavaスタックを初期化します。

例えば、文字列を格納するbooksという名前のスタックを作成したい場合は、次のようなコードになります。

Stack<String> books = new Stack<>();

これで新しいスタックが作成されました。このスタックは後入れ先出しの順序でデータを保持します。

補足:Dequeクラスについて

なお、一部の開発者はJavaでstackクラスの代わりにDequeインターフェースを使うことを好みます。

Deque(デック)は両端キューと呼ばれるデータ構造で、スタックに対する利点は、両端のどちらからでも要素の追加・削除ができる点です。これはスタックでは実現できません。

ただし、後述するスタック固有のメソッドを使用すると、コード内でstackクラスを使い続けることになり、プログラムの拡張が難しくなる場合があります。それでも、stackクラスはJavaにおいて幅広い用途を持っています。

Java Stackクラスの主なメソッド

JavaのStackクラスには、スタック内のデータを操作するためのメソッドが多数用意されています。これらは大きく次の2種類に分けられます。

  1. Vectorクラスから継承されたメソッド:StackはVectorクラスを継承しているため、Vectorのメソッドも利用できます。詳細については「Java Vectorクラス」を参照してください。
  2. Stack固有のメソッド:Stackクラスには、このクラス独自の5つのメソッドがあります。以下で順番に解説します。
  • push()
  • pop()
  • peek()
  • empty()
  • search()

特にpush()とpop()は最もよく使われる操作で、それぞれスタックへの要素の追加と削除を行います。

要素を追加する:push()

push()メソッドは、Javaのスタックに要素を追加します。引数は1つで、スタックに追加したい要素そのものを指定します。

例えば、図書館のフィクション書棚にある本のタイトルを格納するスタックを作っているとしましょう。最初の3冊のタイトルを追加するには、次のようなコードを使います。

import java.util.Stack;

class AddBooks {
	public static void main(String[] args) {
		Stack<String> books = new Stack<>();

		books.push("Pride and Prejudice");
		books.push("Nineteen Eighty-Four");
		books.push("The Great Gatsby");

		System.out.println(books);
	}
}

このコードを実行すると、次の出力が得られます。

[Pride and Prejudice, Nineteen Eighty-Four, The Great Gatsby]

まずJavaのスタックモジュールをインポートし、次にAddBooksという名前のクラスを宣言してプログラムのコードを格納します。

その次の行では、文字列値を格納できるbooksという新しいスタックを初期化しています。そしてpush()メソッドを使って、「Pride and Prejudice」「Nineteen Eighty-Four」「The Great Gatsby」の3冊のタイトルをスタックに追加します。最後に、booksスタックの中身をコンソールに出力しています。

要素を削除する:pop()

pop()メソッドは、スタックのトップから要素を取り除きます。このメソッドは、取り除いた要素を戻り値として返します。

例えば、最後に追加した「The Great Gatsby」をスタックから取り除きたいとしましょう。次のコードで実現できます。

class RemoveBooks {
	public static void main(String[] args) {
		Stack<String> books = new Stack<>();

		books.push("Pride and Prejudice");
		books.push("Nineteen Eighty-Four");
		books.push("The Great Gatsby");

		String removed_book = books.pop();
		System.out.println("Books: " + books);
		System.out.println("Removed book: " + removed_book);
	}
}

このコードを実行すると、次の出力が得られます。

Books: [Pride and Prejudice, Nineteen Eighty-Four]
Removed book: The Great Gatsby

この例では、コードがスタックのトップにある要素を取り除いています。スタックのトップにあったのは「The Great Gatsby」です。その後、プログラムは更新後の本のリストを「Books:」に続けてコンソールに出力し、削除された本のタイトルも「Removed book:」に続けて表示します。

スタックのトップの要素を取得する:peek()

スタックを扱っていると、トップにある要素だけを取得したい場面が出てきます。そんなときに活躍するのがpeek()メソッドです。peek()は引数を受け取らず、スタックのトップを「覗き見」して、そこにある要素を返します。

「The Great Gatsby」を削除した後、スタックのトップにどの本があるか確認してみましょう。

import java.util.Stack;

class FindTopBook {
	public static void main(String[] args) {
		Stack<String> books = new Stack<>();

		books.push("Pride and Prejudice");
		books.push("Nineteen Eighty-Four");

		String top_book = books.peek();

		System.out.println("Book at top of stack: " + top_book);
	}
}

このコードを実行すると、次の出力が得られます。

Book at top of stack: Nineteen Eighty-Four

スタックには2つの要素が含まれており、「Nineteen Eighty-Four」がスタックのトップにあります。そのためpeek()メソッドを使うと、プログラムはその本のタイトルを返します。

スタックが空かどうか確認する:empty()

empty()メソッドは、スタックが空かどうかを判定します。

例えば、スタックのデータをいろいろ操作してきた結果、booksスタックにまだ要素が残っているかどうか確認したい場合を考えてみましょう。

スタックが空かどうかをチェックするには、次のようなコードを使います。

import java.util.Stack;

class CheckBooksEmpty {
	public static void main(String[] args) {
		Stack<String> books = new Stack<>();

		books.push("Pride and Prejudice");
		books.push("Nineteen Eighty-Four");

		boolean is_empty = books.empty();

		System.out.println("Is the book stack empty? " + is_empty);
	}
}

このコードを実行すると、次の出力が得られます。

Is the book stack empty? false

booksスタックには2つの値が含まれているため、空ではありません。したがってbooks.empty()はfalseを返します。

要素を検索する:search()

search()メソッドは、スタック内の要素を検索します。引数は1つで、検索したい項目の名前を指定します。戻り値としては、その項目のスタック内での位置(1始まり)を返します。

例えば、「Pride and Prejudice」が本のタイトルのスタックの何番目にあるのか調べてみましょう。

import java.util.Stack;

class FindPrideBookPosition {
	public static void main(String[] args) {
		Stack<String> books = new Stack<>();

		books.push("Pride and Prejudice");
		books.push("Nineteen Eighty-Four");

		int position = books.search("Pride and Prejudice");

		System.out.println("Position of 'Pride and Prejudice': " + position);
	}
}

このコードを実行すると、次の出力が得られます。

Position of 'Pride and Prejudice': 1

スタック内の最初の項目の位置は「1」です。「Pride and Prejudice」はスタックの最初の項目なので、プログラムは1を返します。

まとめ

JavaのStackクラスは、LIFO構造のスタックを作成するために使用されます。この記事では、Javaのスタックの基礎知識とスタックの作成方法を解説し、さらにスタックの内容を取得・操作するための5つのメソッド(push、pop、peek、empty、search)についても紹介しました。

これで、プロのJava開発者のようにスタックを扱うための知識が身につきました。Javaプログラミングについてさらに学びたい方は、公式ドキュメントや関連チュートリアルもぜひ参考にしてみてください。

  1. Javaのsuperキーワードとは?使い方とサンプルコードを徹底解説

    JavaのsuperキーワードとはJavaにおけるsuperキーワードは、サブクラスから直接の親クラス(スーパークラス)のメンバーやコンストラクタへアクセスするために使われる重要なキーワードです。主な役割は以下の3つです。親クラスのインスタンス参照:super変数は、直近の親クラスのインスタンスを参照します。親クラスのメソッド呼び出し:superを使うことで、オーバーライドされた親クラスのメソッドを呼び出せます。親クラスのコンストラクタ呼び出し:super()は親クラスのコンストラクタとして機能し、子クラスのコンストラクタ内では必ず最初の行に記述する必要があります。特に、オーバーライドされたメ

  2. Javaの集約(Aggregation)とは?HAS-A関係の基本をわかりやすく解説

    Javaにおける集約(Aggregation)とは、オブジェクト指向プログラミングにおける「HAS-A関係」を表す概念です。あるクラスが、別のクラスのオブジェクトを「持っている(has-a)」という関係性を指します。まずは具体的な例を見てみましょう。集約のコード例public class Vehicle{} public class Speed{} public class Van extends Vehicle { private Speed sp; }この例では、VanクラスがSpeedクラスのインスタンスをフィールドとして保持しています。つまり、「VanはSpeedを持っている(