Java初学者が簡単なプログラムを作ったときに詰まったところ～オブジェクト指向、クラスの定義、フィールド、メソッドの定義、コンストラクター…etc～

## はじめに

Javaに入門し、基本的な記述方法（MapとかListとかforとかstrieamとか）は掴めたものの、プログラムを実際に組む段になっていろいろ詰まったので、理解を深めることも兼ねてアウトプットしておきます。

## 作成したプログラムの内容

- 図書管理システムを作る
    - 書籍を管理する情報を持つオブジェクト（class）を作って、そこに情報を格納する
    - 図書館見ないなものを作ってそこにBookをListで持つようなものを保持する
    - mainメソッドからこのLibraryclassに対して検索できるようにする。Libraryクラスは書籍検索の機能を持つ
    - タイトル検索、著者検索、番号検索メソッドをLibraryに持たせる
    - それをmainメソッドから実行して、実行結果をコンソールに出力する

## 詰まったところ

### そもそも何をすればいいかわからない

オブジェクト指向については簡単に学んでいたので、まずは課題内容からオブジェクトを作ることから始めました

- 個々の本のオブジェクト：Book class
- 複数のBookをリストで持つオブジェクト：Library class
- プログラムの実行を行うクラス：Main class

### classの定義の方法

新しいJavaクラスのファイルは作成したものの、そこからどう書いたらいいかでまた悩みました。

Bookには”タイトル”、”著者”、”番号”が必要なのは理解できたのですが、どう書いたら、それが実現できるのかわかりませんでした。

```java
public class Book {

  String title;
  String author;
  int id;
  .
  .
  .
```

LibraryはBookのリストを持つので以下のように定義しました

```java
public class Library {

  public List<Book> library = new ArrayList<>();
  .
  .
  .
```

### インスタンスを作るときに初期値をもたせる方法

`new Book()`する際に引数として、タイトル、著者名、番号を渡せるようにしたかったので以下のように記述しました。

```java
  public Book(String title, String author, int id) {
    this.title = title;
    this.author = author;
    this.id = id;
  }
```

上記はコンストラクターというメソッドで、インスタンスを生成する際に呼び出されるようです。

つまり以下のように書くと、

- title：Webを支える技術
- author：山本 陽平
- id： 1

となるようなbook1が生成されます

```java
Book book1 = new Book("Webを支える技術", "山本 陽平", 1)
```

`new Library()`する際に、インスタンスにBookの初期値を持たせたかったので、以下のようにしました。

```java
  public Library() {
    library.add(new Book("静かな森", "山田太郎", 101));
    library.add(new Book("湖の謎", "ジェーン・スミス", 102));
    library.add(new Book("未知への旅", "佐藤花子", 103));
    library.add(new Book("星々の彼方", "エミリー・ブラウン", 104));
    library.add(new Book("忘れられた物語", "田中健一", 105));
    library.add(new Book("暗闇のささやき", "サラ・ウィルソン", 106));
    library.add(new Book("最後の王国", "高橋一郎", 107));
    library.add(new Book("過去の響き", "エマ・マルティネス", 108));
    library.add(new Book("不死鳥の復活", "鈴木二郎", 109));
    library.add(new Book("山の影", "ソフィア・トンプソン", 110));
    library.add(new Book("時を超えて", "伊藤美咲", 111));
    library.add(new Book("海の秘密", "リンダ・クラーク", 112));
    library.add(new Book("魔法の森", "佐々木幸子", 113));
    library.add(new Book("彼方からの声", "メアリー・ルイス", 114));
    library.add(new Book("地平線を追って", "中村真司", 115));
    library.add(new Book("北の空の下で", "パトリシア・ホール", 116));
    library.add(new Book("風の伝説", "村上大輔", 117));
    library.add(new Book("影の王国", "ローラ・エルナンデス", 118));
    library.add(new Book("大地の歌", "リチャード・キング", 119));
    library.add(new Book("永遠の探求", "松本光", 120));
  }
```

### Mainクラスから呼び出せるようにメソッドを記述する方法

最終的にはmainからLibraryに定義したメソッドを呼び出したいのですが、その記述方法でも悩みました。諸々調べた結果以下のことを理解しました

- クラスに含められるもの
    - 今回使うもの
        - フィールド（プロパティ）
        - コンストラクター
        - メソッド
    - 今回使わないもの
        - 初期化ブロック
        - ネストされたクラス
- メソッド
    - 何をアウトプットする必要があり、どんなインプットが必要なのかを明確にすることが大事
        - 何をアウトプットしたいか（返り値）
            - 単に処理をするだけ　⇒　void
            - Bookのリスト　⇒  List<Book>
        - どんなインプットが必要か（引数）
            - 入力されたタイトル　⇒  String title
                - ※このtitleは単なる変数
            - 特に引数不要なら書かなくてもOK

今回の課題では、”タイトル検索、著者検索、番号検索メソッドをLibraryに持たせる”とあったので、Libraryクラスに以下のように記述しました

```java
  public List<Book> findBookByTitle(String title) {
    List<Book> booksListFilteredByTitle = library.stream()
        .filter(book -> book.getTitle().contains(title))
        .toList();

    if (title.isEmpty()) {
      System.out.println("検索語句を入力してください");
      return Collections.emptyList();
    } else if (booksListFilteredByTitle.isEmpty()) {
      System.out.println("条件にマッチする本はありませんでした");
      return booksListFilteredByTitle;
    } else {
      return booksListFilteredByTitle;
    }
  }
  .
  .
  .
  // 長くなるので割愛しますが、同様にfindBookByAuthor(String author),findBookById(int id)も定義しています
```

※いま見ると、`System.out.println()`などのif文以降はmainクラスで行ったほうが良かったように思います。苦し紛れにemptyListを返すような書き方になっています

### 定義したメソッドを別のクラスで呼び出す

Mainクラスのmainメソッドに以下のように記述しました。

```java
Library library = new Library();
Scanner scanner = new Scanner(System.in);
.
.
.
System.out.println("検索したいタイトルを入力してください： ");
String filteringWordInTitle = scanner.next();  // ここでコンソール上でのインプットをfilteringWordInTitlebに代入
List<Book> booksListFilteredByTitle = library.findBookByTitle(filteringWordInTitle);  // filteringWordInTitleをfindBookByTitleメソッドに引数として渡してBookのリストを取得。booksListFilteredByTitleに代入
for (Book book : booksListFilteredByTitle) { // booksListFilteredByTitleをforEachで回して中身のbookの情報を出力
  System.out.println(book);
}
.
.
.

```

## おわりに

Railsでアプリ開発をしていた際には、コンソール上で入力するようなプログラムをゼロから作ることをしていなかったのでとても勉強になりました。

他にも課題でプログラムを作ったので、時間があれば詰まった箇所を残しておこうと思います。

## 参考

**[classの分割について(Java)](**https://qiita.com/o65nakashima/items/182bba3bf49d166348f9#comments**)**