Java List完全ガイド|基本操作から応用・実装クラスまで徹底解説

この記事では、JavaのListの基本概念から使い方、配列との違い、主要メソッドの活用法までを解説します。初心者が要素操作やデータ管理で迷う悩みを解消し、柔軟なコレクション操作のスキルを習得できます。

目次

JavaのListとは

java+list+arraylist

Listインターフェースの基本概念

JavaにおけるListは、コレクションフレームワークの中核を担うインターフェースのひとつで、順序付けられた要素の集合を表します。Listを利用することで、配列のようにインデックスによるアクセスが可能でありながら、可変長で柔軟な要素の管理ができます。特に、要素の追加・削除・検索を行う際に、操作の抽象化が図れる点が大きな特徴です。

また、Listはジェネリクスを利用できるため、任意の型の要素を安全に格納することができます。例えば、List<String>と定義すれば文字列のみを扱うリストとなり、型の不一致によるエラーを防ぐことが可能です。このように、Listは柔軟かつ安全にデータを管理できる仕組みを提供しています。

配列との違いと使い分け方

JavaにはList配列(Array)がありますが、それぞれに得意分野があるため使い分けが重要です。両者の違いを理解することで、適切なデータ構造を選択でき、アプリケーションのパフォーマンスや可読性を向上させることができます。

  • サイズの可変性: 配列は固定長であるのに対し、Listは必要に応じて要素数を変更できます。
  • 操作メソッド: 配列は基本的な要素操作に限られますが、Listaddremoveといった便利なメソッドを多数備えています。
  • 性能面: 配列はメモリ上で連続して要素を格納するため高速アクセスが可能ですが、柔軟性は低いです。一方、Listは利便性が高い反面、実装クラスによっては速度に差が生じることがあります。

そのため、大量のデータを固定的に扱う場合は配列、柔軟にデータを追加・削除したい場合やコレクションAPIを活用したい場合はListを選択するのが一般的です。

ListとArrayListの関係

Listはあくまでインターフェースなので、そのままではインスタンスを生成できません。具体的な利用には、ArrayListLinkedListといった実装クラスを使用します。その中でも最も頻繁に利用されるのがArrayListです。

ArrayListは内部的に配列を利用しており、ランダムアクセスが高速であることが特徴です。その一方で、要素の削除や挿入を頻繁に行う場合は、再配置(シフト)にコストがかかるため注意が必要です。そのため、Listインターフェースとして宣言し、実際の実装には用途に応じてArrayListなどを代入するのがベストプラクティスとされています。

List<String> names = new ArrayList<>();
names.add("Taro");
names.add("Hanako");

このように宣言することで、将来的に他のList実装(例えばLinkedList)へ容易に切り替えられる柔軟性を持たせることができます。

Listの生成と初期化方法

java+list+array

空のListを作成する方法

JavaでListを扱う際、まず最初に覚えておきたいのが「空のList」を生成する方法です。空のListは、要素を後から追加したい場合や、初期状態ではデータが存在しないことを明示したい場合に便利です。代表的な生成方法は以下の通りです。

// ArrayListを使って空のListを作成する方法
List<String> list1 = new ArrayList<>();

// Immutable(変更不可)の空Listを作成する方法
List<String> list2 = Collections.emptyList();

// Java 9以降で利用できる空のListの作成
List<String> list3 = List.of();

ArrayListを利用した場合は後から要素追加が可能ですが、Collections.emptyList()List.of() で作成したListは変更不可のため、追加・削除操作を行うとUnsupportedOperationExceptionが発生します。用途に応じて使い分けることが重要です。

初期値を持つListの作り方

ある程度のデータを最初から格納しておきたい場合には「初期値を持つList」を作成するのが便利です。この場合の主な記述方法には以下のようなものがあります。

// Arrays.asListを利用する
List<String> list1 = Arrays.asList("Java", "Python", "C++");

// List.ofを利用(Java 9以降)
List<String> list2 = List.of("Java", "Python", "C++");

// ArrayListに初期値をセット
List<String> list3 = new ArrayList<>(Arrays.asList("Java", "Python", "C++"));

Arrays.asListList.ofで生成したListはサイズ固定または不変であるため、要素の追加・削除はできません。一方で、new ArrayList<>を利用した場合は、初期値をセットした後でも自由に操作可能です。この違いを理解して選択することで、エラーを防げます。

配列からListへ変換する方法

既に配列としてデータを持っている場合、それをそのままJavaのListに変換したいケースも多いでしょう。変換には主にArrays.asList()を利用します。

String[] array = {"Java", "Python", "C++"};
List<String> list = Arrays.asList(array);

ただし、この場合のListはサイズ固定となり、要素追加・削除ができません。もし可変のListが必要であれば以下のように変換してから利用します。

List<String> list = new ArrayList<>(Arrays.asList(array));

これにより、自由に追加や削除が可能となり、柔軟に運用できます。

Listから配列へ変換する方法

逆に、JavaのListを配列に変換することもよくあります。主に外部ライブラリとの連携や、配列を必要とするメソッドに渡す場合に利用されます。変換の基本はtoArray()メソッドです。

List<String> list = Arrays.asList("Java", "Python", "C++");

// Object型の配列に変換
Object[] array1 = list.toArray();

// 文字列型の配列に変換
String[] array2 = list.toArray(new String[0]);

引数なしのtoArray()Object[]を返すため、キャストが必要になることがあります。一方、toArray(new String[0]) のように型を指定すれば、キャスト不要で安全に利用できます。ジェネリクスの恩恵を受けて、型安全に扱える点が大きなメリットです。

Listの基本操作

java+list+tutorial

要素の追加

addメソッドで要素を追加する

JavaのListでは、最も基本的な操作としてaddメソッドを使って要素を追加できます。リストの末尾に新しい要素を加えるだけでなく、挿入する位置をインデックスで指定することも可能です。
例えば、list.add("Apple");と記述すれば要素が末尾に追加され、list.add(1, "Banana");とすればインデックス1の位置に要素を挿入します。
この柔軟性により、JavaのListは配列と比べて直感的に操作できる点が特徴です。

addAllメソッドでまとめて要素を追加する

複数の要素を一度にリストへ追加したい場合は、addAllメソッドが便利です。既存のリストやコレクションをそのまままとめて挿入できるので、大量のデータを扱う際にコードを簡潔にできます。
例えば、list.addAll(otherList);のように書けば、別のリストの要素すべてを一括で追加できます。また、インデックスを指定することで、特定の位置にまとめて挿入することもできます。
この方法を活用することで、処理効率が向上し可読性の高いコードを実現できます。

要素の取得

getメソッドで指定位置の要素を取得する

リストに格納した要素を取り出すには、getメソッドを使用します。引数にインデックスを渡すことで、その位置に格納されている要素を取得できます。
例えばlist.get(0);と書けば、リストの先頭にある要素を取得できます。
ただし、指定したインデックスが範囲外の場合はIndexOutOfBoundsExceptionが発生するため、事前に範囲を確認することが重要です。

sizeメソッドで要素数を確認する

リストの現在の要素数を知りたいときはsizeメソッドを利用します。このメソッドはリストに格納されている要素の数を整数値で返すため、ループ処理や境界チェックに欠かせません。
例として、for (int i = 0; i < list.size(); i++) { ... }のように記述すれば、リスト全体を順番に処理できます。

isEmptyメソッドで空かどうか調べる

リストが空であるかを判定するには、isEmptyメソッドが有効です。要素がひとつも含まれていない場合はtrueを返し、そうでなければfalseを返します。
このメソッドは、データを扱う前の安全確認として利用されるケースが多く、例外エラーを未然に防ぐのに役立ちます。

要素の更新

setメソッドで要素を置き換える

既存の要素を新しい値に変更したい場合は、setメソッドを利用します。インデックスを指定して、その位置の要素を任意の値に置き換えることが可能です。
例えばlist.set(1, "Orange");と書けば、2番目の要素が「Orange」に置き換わります。
これは配列と同じように固定位置の値を簡単に更新できるため、特定の位置を操作したいケースに適しています。

要素の削除

removeメソッドで特定要素を削除する

不要になった要素を取り除く場合はremoveメソッドが使えます。インデックスを指定して削除する方法と、オブジェクトそのものを指定して削除する方法の2種類があります。
例えばlist.remove(0);は先頭の要素を削除し、list.remove("Apple");は最初に一致した「Apple」を削除します。

clearメソッドですべて削除する

リストの全要素をまとめて削除したい場合は、clearメソッドを使用します。これにより、リストが空の状態になり、その後isEmptyで確認するとtrueが返却されます。
大量データをリセットしたいときに効率的な手法です。

distinct・retainAllで重複や不要要素を削除する

重複要素を整理したい場合は、JavaのStream APIとdistinct()を利用すると便利です。また、retainAllを用いれば、特定のリストやコレクションに含まれる要素だけを残し、それ以外を削除することができます。
例えば、フィルタリング処理や重複データの除去に適しており、データの整合性を保ちながら効率的にリストを扱えます。

要素の検索

containsメソッドで存在確認を行う

特定の要素がリストに含まれているかを確認する際はcontainsメソッドを使用します。返り値がtrueなら対象の要素が存在し、falseなら存在しません。
例えばlist.contains("Apple");と書けば、リストに「Apple」が含まれているかを判定できます。
データの有無を確認する処理や条件分岐の実装に多用されるメソッドです。

Listの応用操作

java+list+tutorial

並び替え

sortメソッドで昇順・降順に並べ替える

JavaのListを効率的に並べ替えるには、Collections.sort()List.sort()メソッドを活用します。デフォルトではリスト要素の自然順序(数値なら小さい順、文字列なら辞書順)で並び替えられます。独自の並び順を設定したい場合はComparatorを渡すことで、昇順・降順を柔軟に指定できます。

List<Integer> numbers = Arrays.asList(5, 3, 8, 1);
numbers.sort(Comparator.naturalOrder()); // 昇順 [1, 3, 5, 8]
numbers.sort(Comparator.reverseOrder()); // 降順 [8, 5, 3, 1]

このようにsortメソッドを使えば柔軟かつ効率的にリストを整列できるため、検索や分析などの前処理に役立ちます。

reverseメソッドで逆順に並べ替える

元の順序を単純に逆転したい場合は、Collections.reverse()メソッドを利用します。これはソートではなく「並び順の反転」であるため、文字列や数値の大小は関係せず、単純にリストの末尾から前に並び替える点に注意が必要です。

List<String> names = Arrays.asList("A", "B", "C");
Collections.reverse(names); // [C, B, A]

例えば最新のデータをリスト末尾に追加しているケースなどでは、この逆順操作により最新データから順に処理を実行できるため、ログ解析や履歴表示などの用途に便利です。

要素を加工・一括処理する

forEachメソッドで全要素に処理を適用する

リストの全要素に同じ処理を施したい場合、forEachメソッドが有効です。ラムダ式と併用することで、簡潔に要素の出力や変換を記述できます。

List<String> items = Arrays.asList("apple", "banana", "orange");
items.forEach(item -> System.out.println(item.toUpperCase()));

従来のループに比べて可読性が向上するため、ストリーム処理や並列処理とあわせて利用するケースが増えています

replaceAllメソッドで要素をまとめて変更する

全ての要素に対して一括で変更を行いたい時はreplaceAllが活躍します。各要素を引数に取り、変換後の要素を返すラムダ式を記述すれば、新しいリストを作らなくても要素全体を更新できます。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
numbers.replaceAll(n -> n * 2); // [2, 4, 6, 8]

繰り返し処理の中で要素を書き換えるコードを書く必要がないため、簡潔かつ安全に一括変換を行えるのが大きなメリットです。

部分的な操作

subListメソッドで一部を切り出す

リストの一部だけを取り出して処理したい場合には、subListメソッドを利用します。指定した開始位置から終了位置までの要素を新しいビュー(部分的なリスト)として取得できます。

List<String> fruits = Arrays.asList("apple", "banana", "orange", "grape");
List<String> subset = fruits.subList(1, 3); // [banana, orange]

注意点として、この部分リストは元のリストと同じデータを共有しているため、片方を変更するともう片方も影響を受けます。完全に独立したリストが必要な場合はnew ArrayList>(subList)とするのが安全です。

cloneやcopyOfでListをコピーする

リスト全体を別オブジェクトとして保持したい場合はコピーを作成するのが一般的です。ArrayListにはclone()メソッドがあり、シャローコピーを取得できます。また、List.copyOf()を用いればイミュータブルなコピーを作成可能です。

List<String> original = new ArrayList<>(Arrays.asList("A", "B", "C"));
List<String> copy1 = (ArrayList<String>) ((ArrayList<String>) original).clone();
List<String> copy2 = List.copyOf(original); // 変更不可のコピー

これにより、データの安全なバックアップやスレッドセーフな参照が実現できます。更新不要なリストを扱う場合は、イミュータブルなコピーを利用すると予期せぬ変更を防止できます。

イテレーション処理

java+list+iterator

iteratorで順次処理する方法

JavaのListを扱う際に、最も基本的なイテレーションの方法がIteratorを利用する手法です。Iteratorは、リストの全要素を先頭から順に走査するための仕組みを提供し、要素を操作しながら安全に繰り返し処理できます。

Iteratorを使うメリットは、繰り返し処理中に安全に要素を削除できる点です。通常のfor-eachループでは並行変更が原因でConcurrentModificationExceptionが発生する可能性がありますが、Iteratorではremove()メソッドを通じてその問題を回避できます。


List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
Iterator<String> iterator = list.iterator();

while (iterator.hasNext()) {
    String element = iterator.next();
    if ("B".equals(element)) {
        iterator.remove();  // 安全に削除可能
    }
}

このようにIteratorは、要素の削除や順次処理を行う上で確実かつ汎用的な方法として広く利用されています。

listIteratorで双方向に処理する方法

ListIteratorは、Iteratorの拡張版であり、リストを前方向・後方向の両方にイテレーションできる特徴があります。ArrayListLinkedListなどのList実装に対して柔軟な操作を提供しており、特に要素の更新や挿入を行いたい場合に便利です。

ListIteratorでは以下のような操作が可能です:

  • hasNext()next()で順方向に進む
  • hasPrevious()previous()で逆方向に戻る
  • add()で現在位置に要素を挿入する
  • set()で直前に取得した要素を置き換える

List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
ListIterator<String> listIterator = list.listIterator();

while (listIterator.hasNext()) {
    String element = listIterator.next();
    if ("B".equals(element)) {
        listIterator.add("X");  // Bの後ろにXを追加
    }
}

while (listIterator.hasPrevious()) {
    System.out.println(listIterator.previous());
}

このように、ListIteratorは順方向・逆方向両方からのアクセスに対応し、イテレーション途中の編集を柔軟にサポートします。双方向処理や動的な変更が求められるケースで特に活用できます。

spliteratorによる並列処理

近年のJavaで注目を集めているのがSpliteratorを使ったイテレーション手法です。Spliteratorは「Split + Iterator」の略で、大きなコレクションを分割しながら要素を処理できる仕組みを持っています。これにより効率的な並列処理が可能になります。

SpliteratorはJava 8以降で導入され、Stream APIとの親和性が高いため、大規模データを扱うシナリオに適しています。例えば次のようにして、リストを並列処理にかけることができます。


List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D"));

Spliterator<String> spliterator = list.spliterator();
spliterator.forEachRemaining(System.out::println);

さらに、trySplit()を活用することで、処理対象を分割しマルチスレッド環境で効率的に消化することが可能です。特に膨大なリストデータをシングルスレッドで処理しようとするとパフォーマンスが低下するため、Spliteratorは大規模データを扱うアプリケーションにおいて有用性が高いといえます。

総合すると、Iteratorは基本的な逐次処理、ListIteratorは双方向や編集操作、そしてSpliteratorは並列処理向けと、目的に応じて使い分けることがJavaのListを効率的に扱うポイントとなります。

Listと他のコレクションとの変換

java+list+collection

ListとSetの相互変換

Javaでは、ListSetはよく使われるコレクションですが、それぞれに異なる特徴があります。Listは順序を保持し、重複要素を許容します。一方で、Setは要素の一意性を保証し、重複を許しません。そのため、状況によって両者を相互に変換しながら利用すると効率的です。

例えば、重複を取り除きたい場合にはListをSetに変換するのが有効です。


// ListからSetへ変換
List<String> list = Arrays.asList("A", "B", "A", "C");
Set<String> set = new HashSet<>(list);
// 出力: [A, B, C]
System.out.println(set);

// SetからListへ変換
List<String> listFromSet = new ArrayList<>(set);

このように、new HashSet<>(list) のようなコンストラクタを利用することで簡単に変換が可能です。
一方で、SetからListへ変換することで、インデックスによるアクセスや順序を重視した処理が行えるようになります。
変換後の動作を理解し、重複要素が失われる点や順序が保証されない点に注意して利用することが重要です。

ListとMapの変換方法

Mapはキーと値のペアを保持するデータ構造であり、Listとは異なる性質を持ちます。しかし、データの管理や加工の観点から、両者を変換するケースがあります。
代表的な方法としては、Listの要素をインデックスと関連付けてMapに変換するやり方や、オブジェクトの特定のフィールドをキーとする方法があります。


// ListをMapに変換(インデックス付き)
List<String> list = Arrays.asList("Apple", "Banana", "Cherry");
Map<Integer, String> map = IntStream.range(0, list.size())
        .boxed()
        .collect(Collectors.toMap(i -> i, list::get));
// 出力: {0=Apple, 1=Banana, 2=Cherry}
System.out.println(map);

// Mapの値をListに取り出す
List<String> valuesList = new ArrayList<>(map.values());

// MapのキーをListに取り出す
List<Integer> keysList = new ArrayList<>(map.keySet());

このようにCollectors.toMap()を使うと、簡単にListからMapを生成できます。逆にMapからListへ変換する場合は、values()keySet()を利用します。
実装次第で、データの探索性や加工効率を大きく向上させることが可能です。

実装クラスごとの特徴

java+list+collection

ArrayListの特徴と使い方

JavaのArrayListは、最も一般的に利用されるList実装クラスのひとつです。内部的には可変長の配列を利用しており、要素のランダムアクセスが高速で、インデックスによる操作が得意です。そのため、検索や参照を頻繁に行う用途に適しています。

一方、配列サイズが不足した場合には自動的に拡張されますが、その過程で新しい配列を確保し既存データをコピーする必要があるため、追加や削除のコストが高くなる可能性があります。特に中間に要素を挿入したり削除したりすると、多くのシフト処理が発生する点に注意が必要です。

  • メリット: ランダムアクセス(get/set)が高速
  • デメリット: 中間挿入や削除にコストがかかる
  • 適した用途: 検索中心、読み取りが多く追加・削除が少ないケース

// ArrayListの基本例
import java.util.ArrayList;
import java.util.List;

public class ArrayListExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Java");
        list.add("Python");
        list.add("C++");
        
        System.out.println(list.get(1)); // Python
    }
}

このように、ArrayListは「参照性能」を重視する場合に最適な選択肢です。

LinkedListの特徴と使い方

LinkedListは、データをノード同士のリンク(参照)で接続して管理するList実装クラスです。要素ごとに前後のノードを参照しているため、配列のようなメモリ再配置が不要で、中間への挿入や削除を効率的に行える点が大きな特徴です。

ただし、ランダムアクセスが弱点であり、インデックスで要素を取得する場合にはリストを先頭から順にたどる必要があるため、アクセス速度が遅くなるデメリットがあります。そのため、LinkedListは「頻繁に要素を挿入・削除する」シナリオに適しています。

  • メリット: 削除・挿入が高速(特に先頭・末尾)
  • デメリット: ランダムアクセスが遅い
  • 適した用途: キューやスタック、要素操作が頻繁に行われるケース

// LinkedListの基本例
import java.util.LinkedList;
import java.util.List;

public class LinkedListExample {
    public static void main(String[] args) {
        List<String> list = new LinkedList<>();
        list.add("Node1");
        list.add("Node2");
        list.add(1, "InsertedNode");
        
        System.out.println(list); // [Node1, InsertedNode, Node2]
    }
}

このように、LinkedListは「操作性能」を重視する場合や、スタック・キューのようなデータ構造を実装する際に活躍します。

List利用時の注意点とベストプラクティス

java+list+arraylist

参照型変数としての挙動に注意する

JavaのListは参照型のコレクションであるため、代入や引数渡しの際には挙動に注意が必要です。特に「同じインスタンスを複数の変数で参照しているケース」では、片方で更新した内容がもう片方にも影響します。これにより、意図せずデータが変更されるトラブルが発生する可能性があります。

例えば、以下のようなケースです。


List<String> listA = new ArrayList<>();
listA.add("Java");
List<String> listB = listA;  // listAの参照をlistBにも代入
listB.add("List");

System.out.println(listA); // [Java, List]

このように、listBを変更するとlistAの内容も変化します。コピーしたい場合はnew ArrayList<>(元のリスト)といった方法で新しいインスタンスを作成するのがベストプラクティスです。

パフォーマンスを考慮した選び方

JavaのListにはArrayListLinkedListなど複数の実装があります。それぞれの特性を理解し、用途に応じて最適なものを選択することがパフォーマンス改善につながります。

  • ArrayList:インデックスによるアクセスが高速で、要素の追加・削除は末尾が得意。ただし、途中での挿入や削除はコストが高い。
  • LinkedList:挿入・削除は効率的だが、ランダムアクセスは遅い。

例えば、検索や順序付きデータの処理が中心ならArrayList、頻繁に途中の要素を追加・削除する処理が多いならLinkedListといった使い分けをするのが推奨されます。また大規模データを扱う場合は、不要なコピーや過剰な容量確保を避ける工夫も必要です。

よくあるエラーと回避方法

JavaのListを扱う際には、いくつかの典型的なエラーに遭遇することがあります。以下は代表的な例とその回避方法です。

  1. IndexOutOfBoundsException

    指定したインデックスが範囲外の場合に発生します。必ずsize()isEmpty()で範囲を確認しましょう。

  2. ConcurrentModificationException

    イテレーション中にListを直接変更すると発生します。変更が必要な場合はIteratorremove()を利用するか、CopyOnWriteArrayListなどのスレッドセーフなクラスを使用するのが適切です。

  3. NullPointerException

    List内にnullを許容した場合、アクセス時に実行時エラーになることがあります。データ整合性を保つために、なるべくnullを格納しない設計を心がけましょう。

このようなエラーを事前に想定してコードを書くことで、堅牢でメンテナンス性の高いプログラムを構築できます。

まとめ

java+list+array

Listの基礎から応用操作までのおさらい

ここまでJavaのListについて、基礎から応用まで幅広く解説してきました。
まず基本として、Listは順序を保持し、重複を許容するコレクションである点が重要です。そのため、配列のようにインデックス指定で要素を扱える利便性を備えつつも、柔軟にサイズが変化するため、可変的なデータ管理に適しています。

一方で操作面では、以下のように基礎から応用まで実用的な手段が揃っています。

  • 要素の追加・削除: add, remove, clear などで柔軟に更新可能
  • 要素の取得・更新: get, set を使った直接操作が可能
  • 検索や確認: contains, isEmpty, size で効率的にチェック
  • 並び替えや一括処理: sort, forEach, replaceAll などで応用的な活用が可能
  • 部分的な操作やコピー: subList, copyOf で必要部分だけを扱える

このように、JavaのListは「自由な要素管理」と「豊富な操作パターン」が揃ったコレクションであり、基礎を押さえた上で応用機能を組み合わせることで、より生産性の高い開発が実現できます。

配列とListを使い分けて開発効率を高める方法

Java開発において、配列とListはどちらも欠かせないデータ構造です。しかし、両者には適材適所があります。
配列は固定長で処理が高速なため、サイズが事前に明確で変動しないケースに適しています。一方で、Listは柔軟な可変性を武器に、データの追加や削除を頻繁に行う場面で効果的です。

実際の開発では以下のように使い分けると効率的です。

  • 配列を選ぶケース: 要素数が固定で、処理速度や軽量性を重視する場合(例: 数値演算用の固定データ)
  • Listを選ぶケース: ユーザー入力や動的データなど、要素数が流動的で操作が多い場合(例: Webアプリの入力リストや検索結果の管理)

さらに、Arrays.asListtoArrayを利用すれば、配列とListの間でスムーズに変換できます。そのため、柔軟に両者を併用する戦略こそが開発効率向上の鍵です。

まとめると、安定した性能が必要な場面では配列、柔軟性や操作性が求められる場面ではList、そして両者を適切に組み合わせることで、Java開発全体の生産性を大きく向上させることができます。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です