今回の記事ではJavaのコンソールアプリ(Twitterみたいな)のサンプルを紹介します。
次のような人が対象になります。
- Javaの基礎文法を一通り学習した
- Java初心者からレベルアップしたい
- 現役エンジニアが書いたコードを見てみたい
この記事を通してサンプルアプリを作ることで、次のようなスキルが身につきます。
- Javaの基本文法がわかる(if, for, while)
- Javaのクラスの使い方がわかる
- オブジェクト指向がわかる
Java初心者としてレベルアップしたい人におすすめの内容となっていますので、ぜひチャレンジしてみてください。
ただしプログラミング初心者の方にとってはやや難易度の高いアプリとなっています。
そのため開発できなかったとしても、全く問題ありません。
解説編を読んでみるだけでもかなり勉強になるので、ぜひ読んでみてください!
今回開発するTwitterのようなコンソールアプリはこんな感じです。
GitHubにコードを全て上げているので、参考にしてみてください。
GitHubのサンプルコード:https://github.com/uhablog/JavaConsoleTwitter
前提条件
今回は次の環境でコンソールアプリを開発しました。
- macOS Ventura 13.4
- Java 17.0.7
ただしWindowsや違うバージョンのJavaでも同じようなコードで開発できます。
Javaをインストールする方法についてはこちらの記事で解説しています。
コンソールアプリの仕様
今回はJavaを使って、Twitterのようなコンソールアプリを開発していきます。
今回作成するコンソールアプリには、次のような機能があります。
- ユーザー登録
- ログイン
- ログアウト
- ツイートする
- ツイートの一覧表示
コンソールアプリを実行すると次のような画面が表示され、入力待ちの状態となります。
ユーザーは実行したい操作を選び、1〜6の数字を入力します。
入力された値に応じて、機能を実行します。
機能の実行が終わると、もう一度実行する操作の選択画面が表示され、ユーザーが次の操作を入力します。
「6:Twitterを終了する」が選択されるまで、繰り返して様々な機能を実行します。
これから各機能の詳細について説明していきます。
機能1:ユーザー登録
ユーザーの登録を行う機能です。
この機能が選択された時は次の2つの入力をユーザーから受け取ります。
- ユーザー名
- パスワード
入力された情報を元に、Listに登録してユーザーを管理します。
ただし同じユーザー名は登録できないようにします。
すでに登録されているユーザー名が登録された場合は、Listへの追加は行わず、エラーメッセージを出力して機能を終了します。
ユーザーの登録が完了したら、登録されているユーザーの一覧を表示して機能を終了します。
機能2:ログイン機能
登録されたユーザーの情報をもとにログインを行う機能です。
この機能が選択された時は次の2つの入力をユーザーから受け取ります。(ここまでは機能1と同じ)
- ユーザー名
- パスワード
入力されたユーザー名とパスワードが、機能1によってすでに登録されているユーザーと一致する場合はログイン成功です。
どちらかの入力が間違っている場合は、ログインが失敗し機能が終了します。
機能3:ログアウト機能
ログインしている状態であれば、ログイン状態を破棄します。
機能4:ツイート機能
ツイート内容をユーザーが入力し、ツイートを行います。
ただしユーザーがログインしていない場合は、ツイートすることができません。
ユーザーがツイートを入力したら、それをList形式で保存します。
Listにはツイートの内容とツイートした際にログインしていたユーザーのユーザー名を保持しておきます。
機能5:ツイートの一覧表示機能
機能4を使って、ツイートされた内容を一覧で表示します。
表示する際はツイートの内容とツイートしたログインユーザー名を表示します。
全てのツイートを表示して、機能を終了します。
この5つの機能を通して、コンソール版のTwitterを作ってみましょう!
今回のコンソールアプリを開発するためには、冒頭で述べた通り次のような知識が必要になります。
- if文やfor文といった基礎的なJavaの文法
- クラスやインスタンスに関する理解
- オブジェクト指向的なプログラミングができること
まず最初はあなた自身でチャレンジしてみて、開発できるかどうか腕試しをしてみてください。
ただし正直なところプログラミング初心者の方が基礎的な内容を学んだ後にこれを作れるかというとかなり難しいのではないかと考えています。
多分というより確実に、過去の僕だったら絶対にできません。
このコンソールアプリが作れなかったからといって、自信を失う必要はありません!
チャレンジしてみてできなかった人や開発できた人は次の章からの各クラスや処理の解説に進んでみてください。
開発できた人もできなかった人もかなり勉強になる内容となっています!
Javaで作るコンソールアプリ:解説編
ここからはサンプルアプリの解説を行います。
コードはGitHub上にあるので合わせて確認してみてください。
サンプルコード:https://github.com/uhablog/JavaConsoleTwitter
作成したクラスとその役割
今回のアプリでは合計で6個のクラスを作成しました。
- Mainクラス:最初に呼び出されるmainメソッドを持つ
- TwitterControllerクラス:アプリ全体の制御を行うクラス
- Tweetクラス:各ツイート情報を表現するクラス
- TweetManagerクラス;ツイートに関する機能を実行するクラス
- Userクラス:各ユーザー情報を保持するクラス
- UserManagerクラス:ユーザーに関する機能を実行するクラス
ここからは各クラスの詳細について解説していきます!
Mainクラス
mainメソッドを持つクラスです。
アプリが実行された際に、このmainメソッドが実行されて、アプリが開始します。
import controller.TwitterController;
public class Main {
public static void main(String[] args) {
// controllerをインスタンス化してアプリを開始する
TwitterController controller = new TwitterController();
controller.start();
}
}
処理の内容としてはTwitterControllerクラスをインスタンス化してstartメソッドを実行します。
TwitterControllerクラスのstartメソッドで実際の処理を行なっていきます。
TwitterControllerクラス
まずは全体のコードを貼り付けます。
package controller;
import manager.TweetManager;
import manager.UserManager;
import model.User;
import java.util.Scanner;
public class TwitterController {
private UserManager userManager;
private TweetManager tweetManager;
private String loginUsername;
/**
* コンストラクタでUserManagerクラスとTweetManagerクラスを初期化してフィールドで保持する
*/
public TwitterController(){
this.userManager = new UserManager();
this.tweetManager = new TweetManager();
}
/**
* コンソールアプリのメインとなる処理
* ユーザーから操作の番号(1~6)を受け取り対象の操作を実行する
*/
public void start() {
System.out.println("Twitter(Java Console版)へようこそ!");
Scanner scanner = new Scanner(System.in);
// ユーザーから6が入力されるまで、処理を繰り返す
while(true) {
System.out.println("実行する操作を選択してください。");
System.out.println("1:ユーザー登録");
System.out.println("2:ログインする");
System.out.println("3:ログアウトする");
System.out.println("4:ツイートする");
System.out.println("5:ツイートの一覧表示をする");
System.out.println("6:Twitterを終了する");
// ユーザーが選択した処理番号をnextActionとして格納
String nextAction = scanner.nextLine();
// ユーザーの入力が6だった場合、処理を終了する
if ("6".equals(nextAction)) {
break;
}
// ユーザーの入力に応じて処理を分ける
switch (nextAction){
case "1":
// インスタンス変数のuserManagerを使って、ユーザーの登録処理を行う
userManager.userRegister(scanner);
break;
case "2":
// インスタンス変数のuserManagerを使って、ログイン処理を行う
// 戻り値にはログインしたユーザー名が返ってくる
this.loginUsername = userManager.login(scanner);
break;
case "3":
// ログインユーザー名をnullに設定して、ログアウトする
this.loginUsername = null;
break;
case "4":
// ログインしているかチェックする。
if (this.loginUsername == null) {
System.out.println("ログインしてください");
break;
}
//ログインしていた場合、インスタンス変数のtweetManagerを使って、ツイートを行う
tweetManager.tweet(scanner, this.loginUsername);
break;
case "5":
// インスタンス変数のtweetManagerを使って、ツイートを一覧表示する
tweetManager.outputTweetList();
break;
}
}
scanner.close();
}
}
フィールドとコンストラクタ
TwitterControllerクラスは次の3つのフィールドを保持します。
- userManager:ユーザーに関する処理を実行するクラスのインスタンス
- tweetManager:ツイートに関する処理を実行するクラスのインスタンス
- loginUsername:現在ログインしているユーザー名を保持する
コンストラクタでuserManagerとtweetManagerにインスタンス化したものを投入しています。
/**
* コンストラクタでUserManagerクラスとTweetManagerクラスを初期化してフィールドで保持する
*/
public TwitterController(){
this.userManager = new UserManager();
this.tweetManager = new TweetManager();
}
これでmainメソッドでインスタンス化された際に、インスタンス変数に各Managerクラスがインスタンス変数に格納されます。
startメソッド
startメソッドではユーザーから1~6の入力を受けつけ、入力によって実行する操作を制御しています。
インスタンス変数のmanagerクラスを使うことで、それぞれの処理を実行します。
while文を使って無限ループにして、6が入力された場合にbreak文を使って処理が終了です。
/**
* コンソールアプリのメインとなる処理
* ユーザーから操作の番号(1~6)を受け取り対象の操作を実行する
*/
public void start() {
System.out.println("Twitter(Java Console版)へようこそ!");
Scanner scanner = new Scanner(System.in);
// ユーザーから6が入力されるまで、処理を繰り返す
while(true) {
System.out.println("実行する操作を選択してください。");
System.out.println("1:ユーザー登録");
System.out.println("2:ログインする");
System.out.println("3:ログアウトする");
System.out.println("4:ツイートする");
System.out.println("5:ツイートの一覧表示をする");
System.out.println("6:Twitterを終了する");
// ユーザーが選択した処理番号をnextActionとして格納
String nextAction = scanner.nextLine();
// ユーザーの入力が6だった場合、処理を終了する
if ("6".equals(nextAction)) {
break;
}
// ユーザーの入力に応じて処理を分ける
switch (nextAction){
case "1":
// インスタンス変数のuserManagerを使って、ユーザーの登録処理を行う
userManager.userRegister(scanner);
break;
case "2":
// インスタンス変数のuserManagerを使って、ログイン処理を行う
// 戻り値にはログインしたユーザー名が返ってくる
this.loginUsername = userManager.login(scanner);
break;
case "3":
// ログインユーザー名をnullに設定して、ログアウトする
this.loginUsername = null;
break;
case "4":
// ログインしているかチェックする。
if (this.loginUsername == null) {
System.out.println("ログインしてください");
break;
}
//ログインしていた場合、インスタンス変数のtweetManagerを使って、ツイートを行う
tweetManager.tweet(scanner, this.loginUsername);
break;
case "5":
// インスタンス変数のtweetManagerを使って、ツイートを一覧表示する
tweetManager.outputTweetList();
break;
}
}
scanner.close();
}
Tweetクラス
Tweetクラスは一つひとつのツイートを表現するためのクラスです。
package model;
public class Tweet {
private String content;
private String username;
public Tweet(String content, String username) {
this.content = content;
this.username = username;
}
public void outputTweet() {
System.out.println("ユーザー名:" + this.username);
System.out.println("ツイート:" + this.content);
System.out.println();
}
}
フィールドとコンストラクタ
フィールドとして、ツイート内容を保持するcontentとツイートした人を保持するusernameの2つのフィールドを持ちます。
それぞれのフィールドはprivateとして外部から直接参照は不可として、コンストラクタにて値を投入します。
private String content;
private String username;
public Tweet(String content, String username) {
this.content = content;
this.username = username;
}
outputTweetメソッド
自分自身を表示するためのメソッドです。
ツイート内容のcontentやツイート主のusernameはprivateであるため外部からは参照できません。
そのためツイートを表示する際には、表示するためのメソッドを用意することで対応します。
public void outputTweet() {
System.out.println("ユーザー名:" + this.username);
System.out.println("ツイート:" + this.content);
System.out.println();
}
TweetManagerクラス
ツイートに関する処理はTweetManagerクラスで実装していきます。
具体的には
- ログイン中のユーザーでツイートする
- ツイートを一覧表示する
という2つの処理をメソッドを通して実装していきます。
package manager;
import model.Tweet;
import model.User;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class TweetManager {
private List<Tweet> tweets;
public TweetManager() {
tweets = new ArrayList<>();
}
/**
* ツイートするためのメソッド
* 入力された値をツイートし、ユーザー名と一緒に保存する
* @param scanner
* @param username
*/
public void tweet(Scanner scanner, String username) {
System.out.println("Tweet内容を入力してください。");
String tweet = scanner.nextLine();
// Tweetを作成する
Tweet newTweet = new Tweet(tweet, username);
tweets.add(newTweet);
System.out.println("ツイートしました。");
}
/**
* ツイートを一覧表示する
*/
public void outputTweetList() {
System.out.println("ツイート一覧");
// インスタンス変数tweetsをループして一つずつ出力する
for (Tweet tweet: tweets) {
tweet.outputTweet();
}
}
}
フィールドとコンストラクタ
TweetManagerクラスではツイートをList形式で保持するためのフィールドtweetsと
tweetsを初期化するためのコンストラクタです。
private List<Tweet> tweets;
public TweetManager() {
tweets = new ArrayList<>();
}
tweetメソッド
ツイートを行うためのメソッドをtweetメソッドとして実装します。
tweetメソッドでは、ユーザーからの入力を受け付けるためのscannerとログイン中のユーザー名を受け取るusernameを引数として受け取ります。
ユーザーがツイートの内容を入力したら、引数で受け取ったユーザー名とセットでTweetクラスをインスタンス化します。
作成されたtweetを、インスタンス変数のtweetsに追加して処理を終了します。
/**
* ツイートするためのメソッド
* 入力された値をツイートし、ユーザー名と一緒に保存する
* @param scanner
* @param username
*/
public void tweet(Scanner scanner, String username) {
System.out.println("Tweet内容を入力してください。");
String tweet = scanner.nextLine();
// Tweetを作成する
Tweet newTweet = new Tweet(tweet, username);
tweets.add(newTweet);
System.out.println("ツイートしました。");
}
outputTweetListメソッド
ツイートを一覧表示するメソッドとして、outputTweetListメソッドを実装します。
インスタンス変数としてtweetsでツイートを保持しているので、for文を利用して各ツイートを表示していきます。
TweetクラスはoutputTweetメソッドを使って、tweetの中身とユーザー名を表示することができるため、このメソッドを書くtweetに対して実行していきます。
/**
* ツイートを一覧表示する
*/
public void outputTweetList() {
System.out.println("ツイート一覧");
// インスタンス変数tweetsをループして一つずつ出力する
for (Tweet tweet: tweets) {
tweet.outputTweet();
}
}
Userクラス
Userクラスではユーザー1人ひとりを表現するためのクラスとして作成します。
package model;
import java.util.Objects;
public class User {
private String userName;
private String password;
public User(String userName, String password) {
this.userName = userName;
this.password = password;
}
public boolean checkPassword(String password) {
if (this.password.equals(password)) return true;
return false;
}
@Override
public String toString() {
return userName;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
User user = (User) obj;
return userName.equals(user.userName);
}
}
フィールドとコンストラクタ
Userクラスは次の2つのフィールドを保持しています。
- userName
- password
これらはユーザーひとり一人が持っている固有の情報です。
privateにすることで外部からのアクセスを禁止し、コンストラクタにて初期化を行います。
private String userName;
private String password;
public User(String userName, String password) {
this.userName = userName;
this.password = password;
}
checkPasswordメソッド
ログイン時にパスワードが正しいかどうか判定するためのメソッドです。
引数として判定したいパスワードをString型で受け取り、それが正しければtrueを返却します。
正しくない場合は、falseを返却します。
public boolean checkPassword(String password) {
if (this.password.equals(password)) return true;
return false
}
toStringメソッド(オーバーライド)
toStringメソッドをオーバーライドします。
toStringメソッドは全てのクラスが持つメソッドで、オーバーライドすることによって自由な値を返すことができるようになります。
今回はuserNameを返却する処理に変更し、ユーザーの一覧表示の際に使うことにします。
@Override
public String toString() {
return userName;
}
equalsメソッド(オーバーライド)
equalsメソッドもtoStringメソッドと同じく、全てのクラスが持つメソッドです。
今回は同じユーザー名である場合は登録不可にするなど、ユーザー名を持つユーザーは同一とみなしたいです。
引数として受け取ったオブジェクトのuserNameが同じだった場合はtrueを返すような処理としています。
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
User user = (User) obj;
return userName.equals(user.userName);
}
UserManagerクラス
UserManagerクラスではユーザーに関する次の2つの機能を実装します。
- ユーザー登録
- ログイン
ログアウト機能については、TwitterControllerクラスにて制御を行っているため、このクラスでは扱いません。
UserManagerクラスの全体像は次のとおりです。
package manager;
import model.User;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class UserManager {
/**
* すでに登録されているユーザーを保持する
*/
private List<User> userList;
/**
* コンストラクタでは空のArrayListを設定する
*/
public UserManager(){
userList = new ArrayList<>();
}
/**
* ユーザー登録を行うメソッド
* @param scanner
*/
public void userRegister(Scanner scanner) {
// ユーザー名とパスワードの入力を受け付ける
System.out.println("ユーザー登録を行います。");
System.out.println("ユーザー名を入力してください。");
String userName = scanner.nextLine();
System.out.println("パスワードを入力してください");
String password = scanner.nextLine();
// 入力値を元にUserクラスを作成する
User newUser = new User(userName, password);
// 入力されたユーザー名が既に登録されている場合、処理を終了する
if (userList.contains(newUser)) {
System.out.println("ユーザーはすでに登録されています。");
System.out.println();
return;
}
// ユーザーリストにユーザーを追加する
userList.add(newUser);
System.out.println();
// ユーザー一覧を表示する
System.out.println("ユーザー一覧");
for (User user:userList) {
System.out.println(user.toString());
}
System.out.println();
}
/**
* ログイン認証を行う
* @param scanner
* @return 成功時:ユーザー名、失敗時:null
*/
public String login(Scanner scanner) {
System.out.println("ログインを行います。");
System.out.println("ユーザー名を入力してください。");
String userName = scanner.nextLine();
System.out.println("パスワードを入力してください");
String password = scanner.nextLine();
// 入力されたユーザー名とパスワードでUserクラスをインスタンス化
User loginUser = new User(userName, password);
// ログインユーザーが存在しているか確認する
int index = userList.indexOf(loginUser);
// ログインユーザーが存在する
if (index >= 0) {
// ユーザー名が一致しているユーザーを取得
User user = userList.get(index);
// パスワードが一致しているか確認する
boolean loginCheck = user.checkPassword(password);
if (loginCheck) {
System.out.println("ログイン成功!");
// ログインに成功したユーザー名を返却する
return userName;
} else {
System.out.println("ユーザー名もしくはパスワードが間違っています。");
}
} else {
System.out.println("ユーザー名もしくはパスワードが間違っています。");
}
return null;
}
}
フィールドとコンストラクタ
UserManagerクラスはすでに登録されているユーザーをList形式で保持するフィールドを持ちます。
その上で、コンストラクタでは空のListを初期化して格納しておきます。
/**
* すでに登録されているユーザーを保持する
*/
private List<User> userList;
/**
* コンストラクタでは空のArrayListを設定する
*/
public UserManager(){
userList = new ArrayList<>();
}
userRegisterメソッド
ユーザー登録はuserRegisterメソッドを使って行います。
具体的な処理としては、まずはユーザー名とパスワードの入力を受け取ります。
次に受け取った値を使って、Userクラスのインスタンスを作成します。
インスタンス変数のuserListで登録済みユーザーを保持しているので、すでに同じユーザー名を持つユーザーが存在するかどうかのチェックを行います。
containsメソッドではクラスのequalsメソッドを使って、比較を行います。
Userクラスではequalsメソッドをオーバーライドして、ユーザー名が同じであれば同一ユーザーとして判定するというように書き換えています。
そのため同じユーザー名であれば、containsメソッドでtrueとなり、ユーザーが存在するかどうか判定することが可能です。
同じユーザー名のユーザーが存在しなければ、userListにユーザーを追加し、すでに存在していれば登録は行わずに処理を終了します。
/**
* ユーザー登録を行うメソッド
* @param scanner
*/
public void userRegister(Scanner scanner) {
// ユーザー名とパスワードの入力を受け付ける
System.out.println("ユーザー登録を行います。");
System.out.println("ユーザー名を入力してください。");
String userName = scanner.nextLine();
System.out.println("パスワードを入力してください");
String password = scanner.nextLine();
// 入力値を元にUserクラスを作成する
User newUser = new User(userName, password);
// 入力されたユーザー名が既に登録されている場合、処理を終了する
if (userList.contains(newUser)) {
System.out.println("ユーザーはすでに登録されています。");
System.out.println();
return;
}
// ユーザーリストにユーザーを追加する
userList.add(newUser);
System.out.println();
// ユーザー一覧を表示する
System.out.println("ユーザー一覧");
for (User user:userList) {
System.out.println(user.toString());
}
System.out.println();
}
loginメソッド
ユーザーのログインを行う処理はloginメソッドに記述していきます。
ユーザー登録と同じようにユーザー名とパスワードの入力を受け付けます。
その後ListのindexOfメソッドを使って、入力されたユーザー名が登録されているか確認します。
indexOfメソッドでは、存在する場合はそのindex番号を返却し、存在しない場合は-1を返却します。
もしユーザーが存在していた場合は、index番号を使ってユーザーを取得しパスワードが正しいかチェックを行います。
パスワードが正しければログイン成功として、ログインユーザー名を返却します。
ユーザーが存在しない、もしくはパスワードが間違っている場合は、ログイン失敗として処理を終了しnullを返却します。
/**
* ログイン認証を行う
* @param scanner
* @return 成功時:ユーザー名、失敗時:null
*/
public String login(Scanner scanner) {
System.out.println("ログインを行います。");
System.out.println("ユーザー名を入力してください。");
String userName = scanner.nextLine();
System.out.println("パスワードを入力してください");
String password = scanner.nextLine();
// 入力されたユーザー名とパスワードでUserクラスをインスタンス化
User loginUser = new User(userName, password);
// ログインユーザーが存在しているか確認する
int index = userList.indexOf(loginUser);
// ログインユーザーが存在する
if (index >= 0) {
// ユーザー名が一致しているユーザーを取得
User user = userList.get(index);
// パスワードが一致しているか確認する
boolean loginCheck = user.checkPassword(password);
if (loginCheck) {
System.out.println("ログイン成功!");
// ログインに成功したユーザー名を返却する
return userName;
} else {
System.out.println("ユーザー名もしくはパスワードが間違っています。");
}
} else {
System.out.println("ユーザー名もしくはパスワードが間違っています。");
}
return null;
}
コンソールアプリまとめ
今回はJavaを使ってサンプルのコンソールアプリについて解説してきました。
冒頭でも書いたとおり、このアプリは初心者の方にとって少しハードルの高いものになっています。
自分で実装できた方は、かなり実装力があるということで自信を持っていただきたいです!
逆に実装できなかったとしても「自分はプログラマ・エンジニアに向いていないかもしれない」などと思う必要は全くありません。
コードの解説を読んで、それをみながら実装してみるだけでもかなり力になります。
このサンプルアプリを作ることで、次のようなスキルが身についたことが実感できたのではないでしょうか?
- Javaの基本文法がわかる(if, for, while)
- Javaのクラスの使い方がわかる
- オブジェクト指向がわかる
今後もあなたのJavaの学習に役立つ情報を発信していくので、エンジニア大学を活用してぜひエンジニアとしてのデビューを飾れる日が来ることを願っています。