Lesson 4

Java基礎知識

Lesson 4 Chapter 1
基礎知識

このLessonでは実際にプログラミングの書き方や基本的な文法を学んでいきましょう。 プログラミングをするにあたって必要な基礎的な知識を以下で解説します。

プログラムとは

プログラムとは、コンピューターが実行するための指示書のことです。Javaは、コンピューターで動作するプログラムを開発するためのプログラミング言語です。 Javaプログラムは、様々な要素で構成されます。基本的な要素には、クラス、メソッド、変数、制御構造などがあります。詳細についてはこの後の項目で解説していきます。

クラスとオブジェクト

Javaプログラムを書くときの基本的な単位は、「クラス」と呼ばれます。クラスは、オブジェクトを作るための設計図のようなもので、オブジェクトの構造を定めます。オブジェクトは、クラスから作られた実際の対象であり、メソッド(処理)や変数などを持ったものです。 例えば、クラスは「犬」の設計図であり、オブジェクトはその設計図に基づいて作られた「犬の実体」のことです。

Java-4_1

インターフェイス

「インターフェイス」とは、プログラムにおいて、あるクラスやオブジェクトが持つべきメソッドの一覧を定義することができる機能です。 つまり、インターフェイスを使うことで、「これらのメソッドを持つクラスやオブジェクトが必要」というルールを定義することができます。そして、別のクラスやオブジェクトが、そのルールに従ってメソッドを実装することで、インターフェイスを満たすことができます。 例えば、あるプログラムで「飛ぶことができるもの」という概念があった場合、インターフェイスを使うことで、「飛ぶことができるものはfly()というメソッドを持っていなければならない」というルールを定義することができます。そして、別のクラスで「鳥」というクラスを作り、「鳥」クラスが「飛ぶことができるもの」のルールを満たすように、fly()メソッドを実装することができます。 このように、インターフェイスを使うことで、プログラムの様々な要素を柔軟に組み合わせることができます。また、インターフェイスを使うことで、プログラム内の複数の部分が協調して動作するようにすることもできます。

Java-4_2

メソッド

メソッドとは、クラス内に定義された関数のことです。 クラスのメソッドを呼び出すことで、オブジェクトが持つ値を操作できます。 また、メソッドの実装には、引数や戻り値を設定することができます。

例えば、「人」というクラスがある場合、以下のようなメソッドを定義することができます。

java
  [人クラス]
    メソッド:
      - 歩く(): 歩く処理を実行する
      - 走る(): 走る処理を実行する
      - 休む(): 休む処理を実行する
      - 話す(message): 引数で渡されたメッセージを話す

これらのメソッドを呼び出すことで、人オブジェクトの振る舞いを変えることができます。 例えば、人オブジェクトに「歩く()」を呼び出すと、そのオブジェクトは歩く処理を実行します。 また、人オブジェクトに「話す('こんにちは')」を呼び出すと、そのオブジェクトは「こんにちは」と話します。

変数

変数は、データをメモリに格納するために使われるものです。Javaプログラムにおいて、変数には型が必要であり、変数に格納できるデータの種類が限定されます。例えば、整数を格納する場合は int 型の変数を使用します。変数を使うことで、プログラム内でデータを保持することができます。 重要なのは、変数を使うことでデータをメモリ上に確保することができるということです。詳細については、Lesson4 Chapter3で解説します。

制御構造

Javaプログラムでは、if文、for文、while文などの制御構造を使用してプログラムの制御を行います。制御構造は、特定の条件が成立した場合に、指定された処理を実行するようにプログラムを制御するために使用されます。 詳細はLesson4 Chapter5以降で解説します。

エラー処理

Javaプログラムでは、例外処理構文を使用してエラー処理を行います。例外は、プログラムが実行中に予期しない状況が発生した場合に発生します。例外処理を行うことで、プログラムの安定性を高めることができます。

Lesson 4 Chapter 2
パッケージ

Javaにおける「パッケージ」とは、関連するクラスやインターフェースなどを1つのグループにまとめて管理するための仕組みです。

同じパッケージに属するクラスは、パッケージ名で区別されます。たとえば、パッケージ名が「com.example」である場合、そのパッケージに属するクラスのフルネームは「com.example.クラス名」となります。

例えば、以下のようなパッケージがあるとします。

java
  [mypackage]
    - module1.py
      - classA
      - classB
      - func1
    - module2.py
      - classC
      - func2

このようなパッケージ構成では、module1.pyとmodule2.pyという2つのモジュールがmypackageというパッケージにまとめられています。 module1.pyにはclassA、classB、func1というクラスと関数が定義されており、module2.pyにはclassCとfunc2が定義されています。

このようにパッケージを使うことで、クラスや関数を機能別に整理することができます。

パッケージは、クラスやインターフェースなどを効率的に管理することができるため、プログラムの保守性や可読性を向上させることができます。例えば、同じパッケージに属するクラス同士は、互いにアクセス可能なため、クラスの作成や修正時に役立ちます。 また、パッケージを利用することで、プログラムの重複を避けることができ、プログラムの実行速度を向上させることができます。

パッケージの宣言

Javaでパッケージを宣言するには、プログラムファイルの先頭に「package パッケージ名;」という宣言を追加します。たとえば、以下のように記述します。

java
package com.example;

このようにすることで、このプログラムファイルで定義するクラスやインターフェースは「com.example」というパッケージに属することになります。ただし、パッケージ宣言は、プログラムファイルの先頭に一度しか記述できないため、同じパッケージに属する複数のクラスを定義する場合は、それぞれのファイルに同じパッケージ宣言を記述する必要があります。

クラスのインポート

Javaでは、他のパッケージにあるクラスを使う場合には、そのクラスをインポートする必要があります。この「クラスのインポート」は、Javaのプログラムをより使いやすく、保守性の高いものにするための重要な機能です。

クラスをインポートすると、そのクラス名を使うことで、そのクラスの中に定義されたメソッドやフィールドを使用できます。また、クラス名を省略して使用することもできます。

クラスのインポートは、「import」キーワードを使って宣言します。例えば、「java.util」パッケージの「Scanner」クラスを使用する場合、以下のように宣言します。

java
import java.util.Scanner;

このように宣言することで、「Scanner」クラスをクラス名だけで使用することができます。また、「*」を使って、パッケージ内のすべてのクラスをインポートすることもできます。

java
import java.util.*;

ただし、クラス名が同じ場合や、複数のクラスを使用する場合には、インポートの宣言に注意が必要です。

Lesson 4 Chapter 3
変数

Javaにおける変数とは、データをメモリに格納するために使われるもので、プログラム中で何度でも参照や変更ができます。

変数とは、プログラム内で使用するデータを一時的に格納するための領域のことです。Javaでは、データを格納するための変数には型が必要で、例えば整数型や浮動小数点型、文字列型などがあります。変数に初期値を与えることもできます。

変数を使うことで、データの値を必要に応じて変更することができます。変数を使うには、変数の宣言が必要で、その際には変数名と型を指定します。宣言することで、メモリ上に変数を格納する領域が確保されます。

また、変数にはスコープと呼ばれる有効範囲があり、プログラム内のある一部でしか利用できない変数もあります。変数のライフタイムとは、その変数が宣言されてから削除されるまでの期間を表します。これらの概念を理解することで、より正確かつ効率的なプログラムの作成ができます。

変数のスコープ

変数のスコープとは、変数がどの範囲で有効かを示すものです。つまり、変数が定義されてから利用されるまでの期間を示します。スコープによって、変数がどの場所からアクセス可能かが決まります。

一般的に、変数のスコープは変数が定義された場所から、その変数が含まれるブロックの終わりまでです。

変数のライフタイム

変数のライフタイムは、変数が存在する期間を示します。変数が宣言されてから、メモリから消去されるまでの期間を表します。ライフタイムが終了した変数は、その変数に割り当てられたメモリが自動的に解放されます。

一般的に、変数のライフタイムは、その変数のスコープと同じく、変数が定義された場所から、その変数が含まれるブロックの終わりまでです。

変数の宣言

Javaでは、変数を使用する前に変数を宣言する必要があります。変数宣言では、変数の名前、データ型、初期値などを指定します。

以下は、変数を宣言する基本的な構文です。

java
データ型 変数名;

この構文では、まず変数のデータ型を指定し、次に変数名を指定します。変数名は、任意の文字列を使用することができますが、Javaの予約語や数字で始まる名前は使用できません。最後に、セミコロン(;)を記述して文の終了を示します。

例えば、整数値を格納する変数を宣言するには、以下のように記述します。

java
int num;

これにより、整数値を格納するための変数「num」が宣言されます。この変数に値を代入するには、代入演算子「=」を使用します。

初期値を設定する場合は、以下のように宣言します。

java
データ型 変数名 = 初期値;

初期値を指定しない場合、変数には自動的に初期値が設定されます。数値型の場合は0、boolean型の場合はfalse、オブジェクト型の場合はnullとなります。

例えば、int型の変数を宣言して初期値を設定する場合は以下のようになります。

java
int num = 10;

これにより、numという名前のint型の変数が宣言され、初期値として10が代入されます。

さらに、複数の変数を同時に宣言することもできます。

java
int num1, num2, num3;

このようにすることで、3つの整数型変数「num1」「num2」「num3」が宣言されます。それぞれに違う値を代入することもできます。

java
num1 = 1;
num2 = 2;
num3 = 3;
                      

また、変数に格納できるデータの種類は複数あり、以下のように記述することでそれぞれの種類の変数を宣言することができます。

java
int num = 10;      // 整数値を格納する変数
double pi = 3.14;  // 小数値を格納する変数
boolean flag = true;  // 真偽値を格納する変数
String name = "John";  // 文字列を格納する変数

変数は、プログラム中でデータを受け取るための重要な機能であり、多様な種類のデータを扱えるため、Javaにおいて非常に重要な要素の一つとなっています。

メンバ変数、ローカル変数

Javaで使われる変数は、「メンバ変数」と「ローカル変数」の2種類に分けられます。

メンバ変数

メンバ変数とは、クラス内で宣言され、クラス内のどこからでもアクセス可能な変数のことを言います。この変数は、クラスのインスタンス化によって作成されるオブジェクトごとに持たれる値を格納するのに使用されます。メソッド内で変数を宣言することもできますが、その場合はローカル変数として扱われます。

ローカル変数

一方、ローカル変数とは、メソッド内で宣言され、そのメソッド内でしか使えない変数のことを言います。この変数は、メソッドが実行されるたびに初期化され、メソッドの実行が終了すると消滅します。また、ローカル変数には初期値を設定する必要があります。

以下に、メンバ変数とローカル変数の宣言例を示します。

java
public class Example {
    // メンバ変数の宣言
    int memberVariable;

    public void method() {
        // ローカル変数の宣言
        int localVariable = 10;

        // メンバ変数とローカル変数の使用
        memberVariable = localVariable;
        System.out.println(memberVariable);
    }
}

上記の例では、ExampleクラスにmemberVariableというメンバ変数が宣言されています。また、methodメソッド内でlocalVariableというローカル変数が宣言され、値が代入されています。その後、memberVariableにlocalVariableの値が代入され、コンソールに出力されます。

final変数

Javaにおける「final変数」とは、一度値を代入すると変更できなくなる変数のことです。final変数は定数として扱われ、プログラム中で変更することができません。final変数の宣言には「final」キーワードを使用します。

final変数は、一度値を代入した後にその値が変更されることを防ぐことができます。また、final変数はプログラム中で使用される値が固定されるため、プログラムの保守性や可読性を高めることができます。final変数は、通常、定数の値やオブジェクトの参照を格納するために使用されます。

以下は、final変数の宣言と使用例です。

java
final int MAX_COUNT = 10; // final変数の宣言
final String MESSAGE = "Hello, World!"; // final変数の宣言

int count = 0; // 通常の変数の宣言
count = MAX_COUNT; // final変数の値を代入

System.out.println(MESSAGE); // final変数の値を表示

上記の例では、MAX_COUNTとMESSAGEはfinal変数として宣言され、値が代入された後に変更されることはありません。また、count変数にはMAX_COUNTの値が代入され、MESSAGEは文字列として表示されます。

varを使用した型推論

「var」は、Java 10から導入されたキーワードで、変数の宣言時に型推論を使用することができます。つまり、変数に代入される値から型を自動的に推論して、型宣言を省略することができます。

例えば、以下のように変数を宣言することができます。

java
var num = 10; // numの型は自動的にint型に推論される
var str = "Hello"; // strの型は自動的にString型に推論される

ただし、変数の宣言時に値が代入されていない場合、コンパイル時に型推論ができないため、エラーが発生します。また、varで宣言された変数は、再代入が可能な場合でも型推論された型と同じ型でなければなりません。

java
var x; // エラー:varで宣言された変数には初期値が必要です
var y = null; // エラー:nullの型が明示されていません
var z = 10; 
z = 20; // OK:zはint型に推論されているため再代入可能

なお、varを使用した場合でも、型宣言を明示的に書くこともできます。ただし、varと型宣言を併用する場合、型宣言の右辺とvarで宣言された変数に代入される式の型が一致していなければなりません。

java
var i = (int) 3.14; // キャスト(明示的な型変換)してint型にする

Lesson 4 Chapter 4
データ型

Javaには、プログラムで扱う様々な種類のデータに対応するデータ型が用意されています。例えば、整数や小数を扱うためのintやdouble、文字列を扱うためのStringなどがあります。

Javaには基本型と参照型の2種類のデータ型があります。

  • 基本型: 整数型(int, longなど)、浮動小数点型(float, doubleなど)、文字型(char)、真偽値型(boolean)があります。これらは、値そのものを格納するデータ型です。
  • 参照型: オブジェクトを参照するためのデータ型で、文字列(String)や配列(ArrayList)などが含まれます。参照型は、オブジェクトを参照するためのアドレスを格納するため、基本型よりもメモリ使用量が大きくなることがあります。

データ型を選択する際には、データの種類や扱う範囲、精度を考慮して適切なものを使用することが重要です。 例えば、数値を大量に扱う場合には、long型やdouble型を使用する方が適切です。また、データ型の選択はメモリ使用量やプログラムの動作速度にも影響を与えるため、プログラムの最適化を図る上でも重要な要素となります。

データ型 説明
byte 8ビットの整数値を表現する byte num = 10;
short 16ビットの整数値を表現する short num = 100;
int 32ビットの整数値を表現する int num = 1000;
long 64ビットの整数値を表現する long num = 100000L;
float 単精度浮動小数点数を表現する float num = 1.23f;
double 倍精度浮動小数点数を表現する double num = 1.23;
char Unicode文字を表現する char ch = 'A';
boolean 真偽値を表現する boolean flag = true;

基本型

Javaのデータ型には、基本型と参照型があります。基本型とは、値そのものを表すデータ型のことで、参照型とは、オブジェクトのアドレスを表すデータ型のことです。ここでは基本型について説明します。

Javaの基本型には、以下の8つの型があります。

  • byte: 8ビットの符号付き整数型
  • int: 32ビットの符号付き整数型
  • long: 64ビットの符号付き整数型
  • float: 32ビットの浮動小数点数型
  • double: 64ビットの浮動小数点数型
  • char: 16ビットのUnicode文字型
  • boolean: trueまたはfalseを表す真偽型
  • short: 16ビットの符号付き整数型

それぞれの型には、表現できる値の範囲や精度が異なります。以下の表は、基本型の特徴をまとめたものです。

データ型 記述方法 ビット数 値の範囲 デフォルト値
byte byte n = 0; 8 -128~127 0
short short n = 0; 16 -32768~32767 0
int int n = 0; 32 -2147483648~2147483647 0
long long n = 0L; 64 -9223372036854775808~9223372036854775807 0L
float float n = 0.0F; 32 1.4E-45~3.4028235E38 0.0F
double double n = 0.0; 64 4.9E-324~1.7976931348623157E308 0.0
char char c = 'a'; 16 Unicodeの範囲内 '\u0000'
boolean boolean b = true; 1 true/false false

参照型

参照型はオブジェクトを参照するための型です。

参照型とは、Javaでオブジェクトを扱うための型です。オブジェクトとは、データやそれに関する操作をまとめたもののことです。参照型は、オブジェクトを扱うための機能を提供します。基本型よりも高度な機能を持っており、Javaのクラスライブラリには多数の参照型が用意されています。具体的な参照型の例を以下に示します。

以下に、参照型の代表的な型とその使い方を説明します。

String型:

文字列を表す型で、文字列の結合や分割などの操作ができます。

ArrayList型:

可変長の配列を表す型です。要素の追加や削除が可能です。

HashMap型:

キーと値のペアを格納する型です。キーを指定することで、対応する値を取り出すことができます。

Object型:

Object型とは、Java言語で使われる全てのクラスのスーパークラスです。つまり、どのような種類のオブジェクトでも、Object型に代入することができます。例えば、StringやIntegerなどのクラスもObject型に属しているため、それらのオブジェクトもObject型の変数に代入できます。

参照型は、以下のように表されます。

データ型 説明
String 文字列を表す型
ArrayList 可変長の配列を表す型
HashMap キーと値のペアを格納する型
Object Javaの全てのクラスのスーパークラス

参照型は、基本型と異なり、オブジェクトを参照するための変数として扱われるため、メモリ使用量が基本型よりも多くなります。また、参照型の変数は、nullという値を代入することができます。nullとは、変数がオブジェクトを参照していないことを表す特別な値であり、NullPointerExceptionという実行時のエラーを防ぐために使用されます。

型変換

Javaでは、データ型の変換が必要な場合があります。例えば、int型の変数とdouble型の変数を計算する場合、両方の変数を同じ型に変換する必要があります。このような場合、変換が自動的に行われる場合と、明示的に変換する必要がある場合があります。

Javaの型変換には、以下の2つの種類があります。

暗黙的な型変換(自動的な型変換)

暗黙的な型変換は、Javaが自動的に行う型変換です。変換元のデータ型が変換先のデータ型より値の範囲が小さい場合、Javaは自動的に変換を行います。例えば、int型の変数をdouble型の変数に代入する場合、Javaは自動的にint型をdouble型に変換します。

以下は、暗黙的な型変換の例です。

java
int num1 = 10;
double num2 = num1;  // num1がdouble型に自動的に変換される

明示的な型変換(キャスト)

明示的な型変換は、開発者が明示的に指定する型変換です。変換元のデータ型が変換先のデータ型より大きい場合、Javaは自動的に変換を行うことができないため、開発者が明示的に変換を指定する必要があります。このような型変換をキャストと呼びます。

以下は、明示的な型変換(キャスト)の例です。

java
double num1 = 10.5;
int num2 = (int)num1;  // num1がint型にキャストされる

注意点として、キャストはデータ型の範囲を超えた場合に情報の欠落を引き起こす可能性があります。また、参照型の場合には、キャストによって異なる型のオブジェクトを参照することができるため、注意が必要です。

以上がJavaの型変換についての基本的な説明です。

ジェネリクス

ジェネリクスは、Javaにおける型安全性を強化するための機能です。ジェネリクスを使用することで、コンパイル時に型のチェックが行われ、実行時に例外が発生する可能性が減ります。

具体的には、ジェネリクスを使用することで、クラスやメソッドの引数や戻り値の型を、より具体的に指定することができます。これにより、コード内で使用される型に関する情報が明確になり、コンパイラがそれに基づいて型チェックを行うことができます。

例えば、以下のようにListクラスを使用する場合を考えてみましょう。

java
List list = new ArrayList();
list.add("apple");
String fruit = (String) list.get(0);

このコードでは、Listには何の型の要素が入っているかが明示されていません。そのため、要素を取り出す際には、Object型として取り出し、String型にキャストする必要があります。

一方、ジェネリクスを使用した場合は、以下のようになります。

java
List<String> list = new ArrayList<>();
list.add("apple");
String fruit = list.get(0);

この場合、Listに格納される要素の型をString型で指定しているため、要素を取り出す際にはキャストする必要がありません。

ジェネリクスは、コレクションやマップなどのデータ構造を扱う場合に特に有用ですが、クラスやメソッドの戻り値や引数にも使用することができます。また、複数の型パラメータを使用することもできます。

java
public class Pair<K, V> {
    private K key;
    private V value;

    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    public K getKey() { return key; }
    public V getValue() { return value; }
}

上記の例では、ジェネリクスを使用したPairクラスを定義しています。このクラスは、キーと値のペアを表現するために使用されます。型パラメータKとVは、それぞれキーと値の型を表しています。これにより、どのような型のキーと値でも受け入れることができます。

コレクション

コレクションとは、複数の要素を格納できるオブジェクトです。例えば、リストやセットがあります。リストは、要素を順序を持って格納することができ、要素の重複を許します。一方、セットは、要素の順序は保証されませんが、重複を許しません。

マップ

マップとは、キーと値のペアを格納するオブジェクトです。キーは重複を許さず、値は重複を許します。例えば、電話帳をイメージすると、電話番号がキーで、その人の名前や住所などが値になります。

リテラル

Javaにおける「リテラル」とは、プログラムで扱うデータの値そのものを表すために使用される、直接的な値のことを指します。 例えば、整数の値「3」や文字列の値「Hello World」といったものが、Javaのリテラルです。

Javaのリテラルは、以下のようにいくつかの種類に分類されます。

整数リテラル

整数の値を表すために使用されます。10進数の他に、8進数や16進数の表現も可能です。

  • 8進数とは、0から7までの数字を使用して表現される整数のことです。

    8進数では、数字の前に0をつけて表現します。 例えば、8進数の10は10進数で8になります。 8進数は、プログラムの中でビット操作を行う場合に使用されることがあります。

  • 16進数とは、0から9までの数字と、AからFまでのアルファベットを使用して表現される整数のことです。

    16進数では、数字の前に0xまたは0Xをつけて表現します。 例えば、16進数の1Aは10進数で26になります。 16進数は、カラーコードや文字コードなどを表す場合に使用されることがあります。

例:

java
int a = 10;      // 10進数の整数リテラル
int b = 012;     // 8進数の整数リテラル(10進数の10と同じ)
int c = 0xA;     // 16進数の整数リテラル(10進数の10と同じ)

浮動小数点リテラル

小数点を含む実数の値を表すために使用されます。浮動小数点数は、float型とdouble型があります。 float型とdouble型の違いは、扱える桁数の違いです。double型は、float型よりも桁数が多いため、より正確な計算が可能です。しかし、double型は、float型よりもメモリを多く消費するため、プログラムの実行速度が遅くなる場合があります。 例:

java
float a = 3.14f;   // float型の浮動小数点リテラル
double b = 3.14;   // double型の浮動小数点リテラル

文字リテラル

1つの文字を表すために使用されます。シングルクォーテーションで囲まれた1文字です。 例:

java
char a = 'A';   // 文字リテラル

文字列リテラル

複数の文字を表すために使用されます。ダブルクォーテーションで囲まれた複数の文字列です。 例:

java
String a = "Hello World";   // 文字列リテラル

真偽値リテラル

真偽値を表すために使用されます。trueとfalseの2つの値しかありません。 例:

java
boolean a = true;   // 真偽値リテラル

これらのリテラルを使用することで、プログラムで扱うデータの値を直接指定することができます。リテラルはJavaにおいて非常に重要な概念であるため、しっかりと理解しておくことが大切です。

Lesson 4 Chapter 5
演算子

Javaにおける「演算子」とは、プログラムで扱うデータを操作するために使用される記号のことを指します。演算子を使用することで、プログラムは値を計算し、比較し、変更することができます。

主な演算子の種類

Javaには様々な種類の演算子がありますが、ここでは主な演算子の種類について説明します。

算術演算子

数値データを扱うための演算子で、足し算、引き算、掛け算、割り算などの基本的な算術演算を行います。

Javaでの算術演算子は、加算(+)、減算(-)、乗算(*)、除算(/)および剰余(%)です。これらの演算子は、数値データ型(整数型、浮動小数点型)に対して使用されます。

例:

java
int a = 10;
int b = 5;
int c = a + b;   // 加算
int d = a - b;   // 減算
int e = a * b;   // 乗算
int f = a / b;   // 除算
int g = a % b;   // 剰余算

比較演算子

値の大小や等しさを比較するための演算子です。 Javaでの比較演算子は、2つの値を比較し、真偽値(true/false)を返します。Javaでの比較演算子には、等しい(==)、等しくない(!=)、より大きい(>)、より小さい(=)、および以下(

例:

java
int a = 10;
int b = 5;
boolean c = a > b;   // aがbより大きいかどうか
boolean d = a == b;  // aとbが等しいかどうか
boolean e = a != b;  // aとbが異なるかどうか

論理演算子

論理演算子は、真偽値データを扱うための演算子で、複数の真偽値を組み合わせて複雑な条件を表現するために使用されます。 Javaでの論理演算子には、論理積(&&)、論理和(||)、および否定(!)があります。

例:

java
boolean a = true;
boolean b = false;
boolean c = a && b;   // 論理積(AND)
boolean d = a || b;   // 論理和(OR)
boolean e = !a;       // 否定(NOT)

代入演算子

代入演算子は、値を代入するための演算子で、変数に値を格納するために使用されます。 Javaでの代入演算子には、等しい(=)、加算して代入(+=)、減算して代入(-=)、乗算して代入(*=)、および除算して代入(/=)があります。

例:

java
int a = 10;
a += 5;   // aに5を加算して、結果をaに代入する(aの値は15になる)
a -= 5;   // aから5を減算して、結果をaに代入する(aの値は10に戻る)
a *= 2;   // aに2を乗算して、結果をaに代入する(aの値は20になる)
a /= 2;   // aを2で割って、結果をaに代入する(aの値は10に戻る)

条件演算子

条件演算子は、条件式を評価して、真偽値に応じて2つの値のどちらかを返します。 Javaでの条件演算子は、三項演算子(式1 ? 式2 : 式3)です。

Javaでの三項演算子の一般的な形は以下の通りです:

java
式1 ? 式2 : 式3

この演算子は、式1が真(true)の場合は式2を、偽(false)の場合は式3を評価し、その結果を返します。つまり、式1が真の場合は式2が、偽の場合は式3が評価されます。

以下は、条件演算子を使用して、2つの数値のうち大きい方を取得する例です。 例:

java
int a = 10;
int b = 20;
int max = (a > b) ? a : b;   // aがbよりも大きい場合はaを、そうでない場合はbをmaxに代入
System.out.println("Max number is: " + max);   //maxの値を表示

ビット演算子

ビット演算子は、整数値を扱うための演算子で、2進数表現のビットごとの操作を行います。 Javaで使えるビット演算子には、以下のものがあります。

  • AND(かつ)」を計算する演算子(&)
  • 「OR(または)」を計算する演算子(|)
  • 「NOT(否定)」を計算する演算子(~)
  • 「XOR(排他的論理和)」を計算する演算子(^)
  • ビットを左にシフトする演算子(
  • ビットを右にシフトする演算子(>>)

以下は、ビット単位の論理積演算子&を使用して、2つの整数のビットごとの論理積を求める例です。 例:

java
int a = 12; // 1100
int b = 25; // 11001
int result = a & b;   // aとbのビットごとの論理積
System.out.println("Result: " + result); // 1000(10進数で8)であり、結果として8が表示される

ビットをシフトする

ビットをシフトするとは、2進数表記の数値の桁を左右に移動させる操作です。 2進数表記の数値は、0と1で表されます。

  • ビットを左にシフトすると、数値の桁が左に移動します。例えば、「1010」を左に1ビットシフトすると、「0100」となります。
  • ビットを右にシフトすると、数値の桁が右に移動します。例えば、「1010」を右に1ビットシフトすると、「1101」となります。

ビットをシフトすると、数値が2のべき乗倍になったり、1/2になったりすることがあります。

  • 例えば、2進数の「0010」を左に1ビットシフトすると、「0100」になり、数値が2倍になります。
  • 逆に、2進数の「0010」を右に1ビットシフトすると、「0001」になり、数値が1/2になります。

これらの演算子はJavaで非常に重要であり、プログラミングの基本的な要素です。演算子を適切に使用することで、複雑な式を簡単に記述し、効率的なコードを作成することができます。

演算子の優先順位

Javaにおいて、演算子には優先順位が設定されており、式の中で複数の演算子が使用された場合に、どの演算子が先に評価されるかが決まります。優先順位が高い演算子が先に評価されます。

以下は、演算子の優先順位を示した表です。優先順位の高い演算子が上に来るようになっています。

優先順位 演算子 説明
1 +(単項)、-(単項)、! 単項演算子
2 *、/、% 乗算演算子
3 +、- 加算演算子
4 >、>>> シフト演算子
5 、>= 比較演算子
6 & ビット論理積
7 ^ ビット排他的論理和
8 | ビット論理和
9 && 論理積
10 ? : 条件演算子
11 =, +=, -=、*=、/=、%=、>=、&=、^=、|= 代入演算子

"=="とequalsメソッドの違い

Javaにおいて、”==”演算子とequalsメソッドはオブジェクトの比較に使用されますが、その振る舞いには大きな違いがあります。

“==”演算子は、比較したい2つのオブジェクトの参照が同じかどうかを比較します。つまり、2つのオブジェクトが同じメモリ上に存在するかどうかをチェックします。例えば、以下のようなコードでは、”s1”と”s2”は別々のオブジェクトを参照しているため、’s1 == s2’はfalseになります。

java
String s1 = new String("Hello");
String s2 = new String("Hello");
System.out.println(s1 == s2); // false

一方、equalsメソッドは、オブジェクトの内容が同じかどうかを比較します。つまり、2つのオブジェクトが同じ値を持っているかどうかをチェックします。例えば、以下のようなコードでは、”s1”と”s2”の内容は同じなので、’s1.equals(s2)’はtrueになります。

java
String s1 = new String("Hello");
String s2 = new String("Hello");
System.out.println(s1.equals(s2)); // true

ただし、equalsメソッドを使用する場合は、そのメソッドがそれぞれのオブジェクトに対して実装されているため、挙動に違いがあることがあります。例えば、Stringクラスでは、equalsメソッドは文字列の内容を比較するように実装されていますが、他のクラスでは異なる実装になっている場合があります。

以上から、”==”演算子はオブジェクトの参照の比較に使用され、equalsメソッドはオブジェクトの内容の比較に使用されることがわかります。適切な場面でそれぞれを使用することで、プログラムの挙動を正しくすることができます。

Lesson 4 Chapter 6
条件分岐

Javaにおける条件分岐は、ある条件が成り立った場合に実行する処理と、成り立たない場合に実行する別の処理を指定するための制御構文です。

Javaには、if文、if-else文、else-if文、switch文の4つの条件分岐があります。

if、if-else、if-else if-else

条件分岐において、特定の条件が満たされた場合に、異なる処理を実行することができます。Javaでは、if文を使用して条件分岐を表現することができます。

以下は、Javaにおける条件分岐の主な形式です。

if文

if文は、指定された条件が真の場合に、指定された処理を実行します。

java
if (条件式) {
    // 条件式がtrueの場合に実行される処理
}

if-else文

if-else文は、条件が真の場合にはifブロック内の処理を、偽の場合にはelseブロック内の処理を実行します。

java
if (条件式) {
    // 条件式がtrueの場合に実行される処理
} else {
    // 条件式がfalseの場合に実行される処理
}

if-else if-else文

if-else if-else文は、複数の条件分岐を含む場合に使用されます。最初の条件が偽の場合に、次の条件を評価し、真であればその条件の処理を実行します。条件がすべて偽である場合は、最後のelseブロック内の処理を実行します。

java
if (条件式1) {
    // 条件式1がtrueの場合に実行される処理
} else if (条件式2) {
    // 条件式1がfalseで、条件式2がtrueの場合に実行される処理
} else {
    // 条件式1と条件式2がともにfalseの場合に実行される処理
}

これらの条件分岐文は、複数の条件に対応することができます。また、条件式には比較演算子や論理演算子などを使用して、複雑な条件を指定することができます。

switch文

Javaにおいて、switch文は特定の変数の値によって分岐先を決定する条件分岐の構文です。switch文は、if文と比較して多くの分岐を持つ場合により簡潔に書くことができます。

以下は、Javaにおけるswitch文の基本的な構文です。

java
switch (式) {
    case 値1:
        // 値1に対応する処理
        break;
    case 値2:
        // 値2に対応する処理
        break;
    // 他のcase文
    default:
        // どのcase文にも一致しない場合の処理
}

switch文では、式の値がcaseの値に一致する場合、そのcase文に対応する処理が実行されます。一致するcaseがない場合、defaultブロック内の処理が実行されます。また、caseブロックの最後にはbreak文を書く必要があります。break文を書かない場合、その後のcase文の処理が続けて実行されてしまいます。

以下は、具体的な例です。

java
int num = 2;
switch (num) {
    case 1:
        System.out.println("numは1です");
        break;
    case 2:
        System.out.println("numは2です");
        break;
    case 3:
        System.out.println("numは3です");
        break;
    default:
        System.out.println("numは1~3の範囲外です");
        break;
}

この場合、numの値が2であるため、"numは2です"というメッセージが出力されます。

break

Javaのbreakは、ループやswitch文の中で使われ、その文の実行を中断し、制御を次の文に移します。つまり、ループ内の処理を途中で終了したり、switch文を抜けたりすることができます。

三項演算子による条件分岐

Javaにおいて、三項演算子を使用することで簡潔な条件分岐を実現することができます。三項演算子は、条件式の真偽に応じて異なる値を返すための演算子で、if文と同じような動作をします。

以下は、三項演算子の基本的な構文です。

java
(条件式) ? trueの場合の値 : falseの場合の値

条件式がtrueの場合には、trueの場合の値が返されます。falseの場合には、falseの場合の値が返されます。

以下は、具体的な例です。

java
int num = 3;
String result = (num > 0) ? "正の数です" : "0または負の数です";
System.out.println(result);

この場合、numが正の数であるため、"正の数です"というメッセージが出力されます。

三項演算子はif文よりも簡潔に書くことができるため、1行のコードで条件分岐を行うことができます。ただし、複雑な条件分岐を行う場合にはif文を使用した方が可読性が高くなることがあります。

Lesson 4 Chapter 7
繰り返し処理

Javaにおける繰り返し処理とは、ある一定の処理を繰り返し実行することを指します。繰り返し処理を使用することで、同じ処理を何度も書く手間を省くことができます。

Javaには主に2つの繰り返し処理があります。1つは「forループ」で、指定した回数だけ処理を繰り返します。もう1つは「whileループ」で、指定した条件が真である限り処理を繰り返します。

繰り返し処理を使用する場合、無限ループに注意する必要があります。無限ループとは、条件式が常に真である場合に発生する無限のループです。無限ループに陥ると、プログラムが永遠に実行され続けるため、注意が必要です。

while、do-while

Javaにおける繰り返し処理は、同じ処理を複数回繰り返して実行することができます。Javaには、whileループとdo-whileループの2種類の繰り返し構文があります。

whileループ

whileループは、指定された条件が真である限り、繰り返し実行されます。

java
while (条件式) {
    // 繰り返し実行する処理
}

例えば、1から10までの数字を順に出力するプログラムをwhileループで書くと以下のようになります。

java
int i = 1;
while (i 

do-whileループ

do-whileループは、まず一度ブロック内の処理を実行し、その後に条件式を評価して、条件が真である限り繰り返し実行されます。

java
do {
    // 繰り返し実行する処理
} while (条件式);

例えば、1から10までの数字を順に出力するプログラムをdo-whileループで書くと以下のようになります。

java
int i = 1;
do {
    System.out.println(i);
    i++;
} while (i 

do-whileループは、少なくとも1回は処理を実行する必要がある場合に有用です。ただし、条件式が常に真である場合、無限ループに陥ることがあるため、注意が必要です。

for、拡張for

Javaにおいて、繰り返し処理を行うためには主にfor文と拡張for文が使用されます。

for文

for文は、あらかじめ指定された回数分、処理を繰り返すために使用されます。for文は以下のような構文を持ちます。

java
for (初期化式; 条件式; 更新式) {
    // 繰り返し処理
}

for文の各要素の意味は以下の通りです。

  • 初期化式

    ループの最初の実行前に一度だけ実行されます。通常、カウンタ変数(何回目の処理かを保存しておく変数)を初期化するために使用されます。

  • 条件式

    ループの各反復で評価され、条件が真の場合にループを続けます。

  • 更新式

    各反復の終わりに実行されます。通常、カウンタ変数を更新するために使用されます。

以下の例は、for文を使用して、1から10までの数を表示する例です。

java
for (int i = 1; i 

この例では、初期化式で変数iを1で初期化しています。条件式でiが10以下の場合にループを続けます。更新式でiを1ずつ増やしています。結果として、1から10までの数が順番に表示されます。

拡張for文

拡張for文は、配列やリストなどのコレクションを繰り返し処理するために使用されます。拡張for文は以下のような構文を持ちます。

java
for (データ型 変数名 : 配列またはコレクション) {
    // 繰り返し処理
}

拡張for文の各要素の意味は以下の通りです。

  • データ型

    配列またはコレクション内の要素のデータ型を指定します。

  • 変数名

    要素を格納するための変数名を指定します。

  • 配列またはコレクション

    繰り返し処理する対象の配列またはコレクションを指定します。

以下の例は、配列を拡張for文を使用して繰り返し処理する例です。

java
int[] array = {1, 2, 3, 4, 5};
for (int num : array) {
    System.out.println(num);
}

この例では、配列array内の要素をnumという変数に順番に代入して、その値を表示しています。結果として、1から5までの数が順番に表示されます

ラベル

Javaにおける「ラベル」とは、コードブロックに対して名前を付け、その名前を利用して、ブロック内の特定の場所にジャンプ(移動)するための機能です。ラベルは主に、複数のループがネストしている場合(ループの中でさらにループを処理している場合)に、内側のループから外側のループまで一気に抜け出したい場合に利用されます。

ラベルを定義するには、任意の識別子の後ろにコロン(:)をつけます。ラベルは通常、forループやwhileループの直前に置かれます。

java
labelName:
for (int i = 0; i 

上記の例では、labelNameという名前のラベルをforループの直前に定義しています。そして、break文にラベル名を指定することで、labelNameというラベルを持つブロックを抜け出しています。

また、ラベルはcontinue文でも利用することができます。次の例は、2重ループ内でcontinue文にラベルを指定し、内側のループだけをスキップしています。

java
outer:
for (int i = 0; i 

上記の例では、outerという名前のラベルを持つループの次のループに進むことで、内側のループだけをスキップしています。こうしたラベルを利用したジャンプは、コードの可読性を低下させる恐れがあるため、慎重に利用する必要があります。

continue

Javaのcontinueは、ループ内で使われ、現在の処理をスキップして次の処理に進みます。つまり、繰り返し処理を行う場合、特定の条件を満たす場合に、その条件の処理をスキップして、次の処理を行うことができます。条件とは、if文やswitch文などで判断するための式のことで、真偽値を返すことができます。

Lesson 4 Chapter 8
配列

Javaにおける「配列」とは、同じ型の複数のデータを格納するための変数の集合です。配列は、データを格納するためのメモリ領域が連続しているため、データのアクセスが高速に行えるという特徴があります。

配列は、宣言時に配列のサイズを指定し、その後、各要素に対してインデックス(データの位置を示すために使われる数字)を使ってアクセスすることができます。配列のインデックスは0から始まり、配列のサイズ-1までの範囲で指定します。

Javaでは、配列の宣言方法は以下のようになります。

java
// 整数型の配列を宣言して初期化する
int[] array1 = {1, 2, 3, 4, 5};

// 整数型の配列を宣言して、サイズだけ指定する
int[] array2 = new int[5];

配列の要素には、以下のようにインデックスを指定してアクセスすることができます。

java
// 配列array1の3番目の要素にアクセスする
int x = array1[2];

// 配列array2の2番目の要素に値を代入する
array2[1] = 10;

配列は、forループなどの繰り返し処理を用いて、一度に複数の要素に対して同じ処理を行うことができます。また、多次元配列や配列の要素として配列を持つことも可能です。

配列の宣言、初期化

Javaにおける配列は、複数の同じ型の値を一つの変数にまとめて管理するために使用されます。配列の宣言と初期化には以下のような方法があります。

配列の宣言

配列を使用するには、まず配列変数を宣言する必要があります。配列変数の宣言には以下のような方法があります。

java
// int型の配列を宣言する
int[] array;

// int型の配列を宣言する別の方法
int array[];

// String型の配列を宣言する
String[] strArray;

// double型の配列を宣言する
double[] doubleArray;

配列の初期化

配列変数を宣言した後、実際に値を代入するには、配列の初期化が必要です。配列の初期化には以下のような方法があります。

静的初期化

静的初期化は、配列を宣言すると同時に値を代入する方法です。

以下はint型の配列を静的初期化する例です。

java
// int型の配列を静的初期化する
int[] array = {1, 2, 3, 4, 5};

動的初期化

動的初期化は、配列を宣言した後に、値を代入する方法です。以下はint型の配列を動的に初期化する例です。

java
// int型の配列を動的初期化する
int[] array = new int[5];

// 配列の各要素に値を代入する
array[0] = 1;
array[1] = 2;
array[2] = 3;
array[3] = 4;
array[4] = 5;

上記の例では、int型の配列を5つの要素を持つ配列として宣言しています。その後、各要素に値を代入しています。

二次元配列の初期化

二次元配列を初期化する場合は、次のように書くことができます。

java
// 二次元配列を初期化する
int[][] array = {{1,2,3}, {4,5,6}, {7,8,9}};

上記の例では、int型の二次元配列を初期化しています。配列の各要素は、{1,2,3}、{4,5,6}、{7,8,9}という3つの1次元配列で構成されています。

多次元配列

多次元配列とは、配列を要素とする配列のことです。つまり、二次元配列は、配列を要素とする配列であり、三次元配列は、二次元配列を要素とする配列であるといったように、階層的に構成されます。

多次元配列の宣言方法は、一次元配列と同様に、要素型に続いて「[ ]」を並べ、階層数だけ指定します。例えば、int型の二次元配列を宣言する場合は以下のようになります。

java
int[][] array2d;

また、初期化する場合は、以下のように書くことができます。

java
int[][] array2d = {{1, 2}, {3, 4}};

この場合、二次元配列の要素数は2行2列であり、array2d[0][0]には1が、array2d[0][1]には2が格納されています。

例えば、以下のような二次元配列は、2行3列の表を表現することができます。

java
int[][] array = {
    {1, 2, 3},
    {4, 5, 6}
};

この場合、array[0][0]は1、array[0][1]は2、array[1][2]は6といったように、インデックスを2つ使って要素にアクセスすることができます。

多次元配列は、行列計算や画像処理など、複雑な処理を行うために利用されます。

ArrayListクラスを利用した可変長配列の作成

「ArrayList」とはJavaの標準ライブラリに含まれるクラスで、可変長の配列を扱うために利用されます。通常の配列とは異なり、宣言時に配列のサイズを指定する必要がなく、要素の追加や削除が簡単にできます。

以下は、ArrayListを利用して可変長配列を作成するための基本的な方法です。

ArrayListのインスタンスを作成する

ArrayListを利用するには、まずArrayListのインスタンスを作成する必要があります。以下のように記述します。

java
ArrayList<Integer> list = new ArrayList<Integer>();

要素を追加する

要素を追加するには、add()メソッドを使用します。以下は、要素を追加する例です。

java
list.add(10);    // 10を追加する
list.add(20);    // 20を追加する
list.add(30);    // 30を追加する

要素を取得する

要素を取得するには、get()メソッドを使用します。以下は、要素を取得する例です。

java
int value = list.get(0);    // 0番目の要素を取得する
System.out.println(value);    // 結果:10

要素を削除する

要素を削除するには、remove()メソッドを使用します。以下は、要素を削除する例です。

java
list.remove(1);    // 1番目の要素を削除する

以上が、ArrayListを利用した可変長配列の作成の基本的な方法です。他にも、ArrayListには様々なメソッドが用意されていますので、必要に応じて利用してください。

Lesson 4 Chapter 9
予約語

Javaの予約語とは、Javaの文法で特別な意味を持つ単語であり、変数やメソッド名として使用することはできません。以下はJavaで使用される主な予約語の一覧です。

カテゴリー 予約語
データ型 boolean, byte, char, short, int, long, float, double, void
制御構文 if, else, switch, case, default, while, do, for, break, continue, return
アクセス修飾子 public, private, protected
クラス、インターフェース関連 class, interface, extends, implements, package, import, new, instanceof, super, this
その他 final, static, synchronized, native, abstract, transient, volatile, strictfp

これらの予約語は、Javaの文法の一部であるため、変数やメソッド名として使用することはできません。予約語を使用したい場合は、文字列として扱う必要があります。

Lesson 4 Chapter 10
ラムダ式

ラムダ式はJava 8から導入された機能で、関数型プログラミングにおいて便利に使われます。ラムダ式は、Javaで「関数」と呼ばれる処理の単位をより簡潔に書くことができる機能です。ラムダ式の導入前には、同じような機能を実現するために匿名クラスという記述方法がありましたが、ラムダ式の方がより簡潔で読みやすいコードを書くことができます。

ラムダ式は、引数として渡される関数を簡潔に表現する方法です。一般的には以下のような構文で書かれます。

java
(引数リスト) -> { 処理 }

例えば、以下のような匿名クラスを使ったコードは、ラムダ式を使うことで以下のように書き換えられます。

【匿名クラスを使ったコード】

java
button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println("ボタンがクリックされました。");
    }
});

【ラムダ式を使用したコード】

java
button.addActionListener((e) -> {
    System.out.println("ボタンがクリックされました。");
});

このように、引数として渡される関数の中身を簡潔に表現することができます。

また、ラムダ式を使うことで、コレクションの要素を簡潔に処理することもできます。例えば、以下のようなコードは、ラムダ式を使うことで以下のように書き換えられます。

【匿名クラスを使ったコード】

java
List<String> list = Arrays.asList("apple", "banana", "orange");
for (String s : list) {
    System.out.println(s);
}

【ラムダ式を使用したコード】

List<String> list = Arrays.asList("apple", "banana", "orange");
list.forEach((s) -> {
    System.out.println(s);
});

このように、ラムダ式を使うことで、より簡潔で読みやすいコードを書くことができます。

関数型インターフェース

関数型インターフェースは、Javaにおける特殊なインターフェースで、1つのメソッドしか持たないインターフェースのことを指します。この1つのメソッドは、関数型インターフェースの実装クラスによって、異なる動作を定義することができます。

関数型インターフェースは、関数として扱うことができます。Java 8以降では、関数型インターフェースを使用することで、ラムダ式やメソッド参照をより簡潔かつ読みやすく記述することができます。

関数型インターフェースを定義するには、@FunctionalInterfaceアノテーションを使用します。このアノテーションは、1つのメソッドしか持たないことを保証するために使用されます。

以下は、関数型インターフェースを使用する例です。

java
@FunctionalInterface
interface MyInterface {
    int calculate(int x, int y);
}

public class Main {
    public static void main(String[] args) {
        MyInterface add = (x, y) -> x + y;
        MyInterface subtract = (x, y) -> x - y;

        System.out.println(add.calculate(5, 3)); // 8
        System.out.println(subtract.calculate(5, 3)); // 2
    }
}

上記の例では、MyInterfaceという関数型インターフェースを定義し、calculateメソッドを持っています。その後、addとsubtractという2つのインスタンスを作成し、それぞれラムダ式で実装しています。

関数型インターフェースを使用することで、コードの可読性が向上するだけでなく、関数型プログラミングの機能を利用して、より簡潔で効率的なコードを記述することができます。

Lesson 4 Chapter 11
モジュールシステム

Java 9から導入された「モジュールシステム」とは、Javaプログラムを構成する部品の1つであり、モジュールと呼ばれる単位でプログラムを管理することができます。モジュールシステムを使用することで、Javaアプリケーションのライブラリやフレームワークなどの依存関係を明示的に宣言し、それらのバージョンの競合を回避することができます。具体的には、モジュールには他のモジュールに提供するインターフェースや必要とする他のモジュールのインターフェースを定義し、依存関係を明示的に宣言することができます。

モジュールは、module-info.javaファイルを使用して定義されます。このファイルには、モジュール名、提供するパッケージ、依存するモジュール、そして必要な場合はモジュール内部でのみ使用されるパッケージなどが含まれます。モジュールシステムを使用するには、Javaの実行環境に対してモジュールパスを指定する必要があります。モジュールパスには、モジュール化されたJARファイルが含まれます。モジュールシステムを使用することで、コードの可読性や保守性も向上することができます。

モジュールシステムは、Javaプログラムの構成要素の一つであり、特に大規模なプログラム開発において、依存関係の解決や競合の回避などを行うために重要な役割を果たします。

モジュールの作成

モジュールは、関連するクラスをひとまとめにして、他のモジュールからのアクセスを制限することができます。 モジュールディレクトリを作成するには、プロジェクトのディレクトリ直下に、モジュール名と同名のディレクトリを作成します。 モジュールを作成するには、以下の手順が必要です。

  1. モジュールディレクトリを作成する
  2. モジュールのソースコードを記述する
  3. モジュールをコンパイルする
  4. モジュールをパッケージ化する

【Eclipseを使用する場合】

  1. Eclipseで新しいJavaプロジェクトを作成します。プロジェクト名を指定したら、「完了」をクリックしてプロジェクトを作成します。(すでに作成済みであれば不要です)
  2. プロジェクトでモジュールを作成するために、新しいフォルダを作成します。フォルダの名前は、モジュール名と同じにすることが一般的です。

以下はモジュールを作成した時のディレクトリ構成の例です。

project/
├── モジュール名/
│   ├── module-info.java
│   ├── パッケージ1/
│   │   ├── クラス1.java
│   │   ├── クラス2.java
│   │   └── ...
│   ├── パッケージ2/
│   │   ├── クラス1.java
│   │   ├── クラス2.java
│   │   └── ...
│   └── ...
└── ...

プロジェクトの直下に、モジュール名と同じ名前のディレクトリを作成します。そのディレクトリには、module-info.javaと呼ばれるファイルが含まれます。また、そのディレクトリ内には、モジュールが提供するパッケージごとにサブディレクトリを作成し、それぞれのディレクトリには、クラスファイルが含まれます。

module-info.javaファイル

モジュール記述ファイル(module-info.java)を作成し、モジュールの名前、依存関係、エクスポートするパッケージなどを定義します。モジュール記述ファイルは、モジュールディレクトリ直下に作成されます。

モジュールを作成する際には、モジュールのルートにmodule-info.javaというファイルを作成する必要があります。このファイルには、以下のような情報を記述します。

  1. モジュール名
  2. モジュールが依存する他のモジュールの情報
  3. モジュールがエクスポートするパッケージの情報
  4. モジュールが使用するサービスの情報

【Eclipseを使用する場合】

module-info.javaファイルを作成するには、以下の手順を実行します。

  1. モジュールフォルダを右クリックし、「新規」を選択します。
  2. 「ファイル」を選択し、「ファイルの名前」に「module-info.java」と入力します。
  3. 「完了」をクリックします。

module-info.javaファイルが作成されるので、必要な情報を記述します。

以下はmodule-info.javaファイルの例です。

module-info.java
module com.example.myapp {
    requires java.base;
    requires transitive com.example.mylibrary;
    exports com.example.mypackage;
}

上記の例では、com.example.myappというモジュールを定義しています。このモジュールはjava.baseモジュールを必要とし、またcom.example.mylibraryモジュールに対しても必要であることを示しています。transitiveキーワードが指定された場合、com.example.mylibraryモジュールに依存する他のモジュールに対しても、com.example.myappモジュールが必要であることを伝えます。

また、com.example.mypackageパッケージを提供することを示すために、exportsキーワードが使用されています。このパッケージは、他のモジュールからアクセス可能であるということを意味します。

このように、module-info.javaファイルは、モジュールの名前、依存するモジュール、提供するパッケージなどを定義するためのファイルです。モジュールシステムを使用する場合には、このファイルを定義することで、依存関係の解決や競合の回避などを行うことができます。

モジュールの実行

モジュールを実行する際には、以下の手順が必要です。

  1. モジュールパスにモジュールを追加する
  2. モジュールを実行する

モジュールパスにモジュールを追加するには、以下のオプションを指定します。

command
--module-path 

モジュールを実行するには、以下のオプションを指定します。

command
--module /

ここで、はモジュール名、はメインクラスの完全修飾名です。

【Eclipseを使用する場合】

モジュールを実行するためには、以下の手順を実行します。

  1. 実行構成を作成します。これは、モジュールを実行するための設定です。
  2. 実行構成の「引数」タブで、--module モジュール名という引数を指定します。

モジュール間の依存関係

モジュールシステムでは、複数のモジュールが互いに依存しあっていることがあります。例えば、あるモジュールAが別のモジュールBに依存している場合、モジュールAはモジュールBのクラスを使用することができます。

依存関係の宣言は、モジュールのmodule-info.javaファイルで行います。依存するモジュールをrequiresキーワードを使って宣言し、モジュール名を指定します。例えば、以下のように記述します。

java
module mymodule {
    requires othermodule;
}

この例では、mymoduleという名前のモジュールが、othermoduleという名前の別のモジュールに依存していることを宣言しています。

依存関係は、依存するモジュールがコンパイルおよび実行時に利用できるようにするために必要です。モジュールのコンパイル時には、すべての依存するモジュールが存在している必要があります。また、実行時には、モジュールローダーによって依存するモジュールが必要に応じてロードされます。

モジュール間の依存関係は、アプリケーションの構造をより明確にするだけでなく、モジュール化されたアプリケーションのセキュリティやメンテナンス性を向上させることができます。

jmodコマンド

「jmod」とは、Java 9から追加されたツールの一つで、モジュールに関する操作を行うためのコマンドです。

具体的には、以下のような操作が可能です。

  • モジュール情報の表示
  • モジュールのパッケージを一覧表示
  • モジュールのアーカイブ化
  • モジュールのアーカイブからの展開
  • モジュールの依存関係の表示

これらの操作を実行するためには、まずjmodコマンドを利用する必要があります。jmodコマンドは、コマンドラインから実行されます。

例えば、以下のようなコマンドを実行することで、モジュールの情報を表示することができます。

command
jmod describe mymodule.jmod

このコマンドは、mymodule.jmodという名前のモジュールを解析し、その情報を表示します。

また、以下のようなコマンドを実行することで、モジュールをアーカイブ化することができます。

command
jmod create mymodule mymodule.jar

このコマンドは、mymoduleという名前のモジュールを、mymodule.jarという名前のアーカイブファイルに変換します。

jmodコマンドは、モジュール開発者や管理者にとって非常に役立つツールであり、モジュールの作成や管理に必要不可欠なものとなっています。

Lesson 4 Chapter 12
正規表現

正規表現は、文字列のパターンを表す表現方法です。Javaでは、正規表現を使用するためにjava.util.regexというパッケージが提供されています。

以下に、よく使われる正規表現の特殊文字とその意味を示します。

特殊文字 意味
. 任意の1文字にマッチする
\d 数字にマッチする
\w 英数字、アンダースコアにマッチする
\s 空白文字にマッチする
^ 行頭にマッチする
$ 行末にマッチする
[ ] 指定された文字クラスにマッチする
[^ ] 指定された文字クラス以外にマッチする
( ) グループ化し、後方参照することができる
* 直前の文字が0回以上繰り返される
+ 直前の文字が1回以上繰り返される
? 直前の文字が0回または1回現れる
{n} 直前の文字がn回現れる
{n,} 直前の文字がn回以上現れる
{n,m} 直前の文字がn回以上、m回以下現れる
| "または"を意味する
\ 特殊文字をエスケープする(例えば.はピリオドにマッチ)

Javaで正規表現を使用する場合、PatternクラスとMatcherクラスを使用します。

以下は、正規表現を使用して文字列のパターンにマッチする例です。

RegexExample.java
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexExample {
    public static void main(String[] args) {
        String text = "The quick brown fox jumps over the lazy dog";
        Pattern pattern = Pattern.compile("fox|dog"); // foxまたはdogにマッチする正規表現
        Matcher matcher = pattern.matcher(text);
        while (matcher.find()) {
            System.out.println("Matched: " + matcher.group());
        }
    }
}

この例では、"fox"または"dog"にマッチする正規表現パターンを作成し、Matcherオブジェクトに適用して、text変数内の文字列にマッチする部分を検索しています。 find() メソッドが true を返す限り、while ループ内で繰り返し処理が実行され、group() メソッドでマッチした部分文字列を取得して表示します。