Java/初級編

出典: フリー教科書『ウィキブックス(Wikibooks)』

この単元で学ぶことは、Javaプログラミングの基礎と初歩的な構文です。 変数、演算、条件分岐、反復処理、型、リテラル、文字列、配列、クラス、例外処理など、プログラミングの基本要素を学びます。 これにより、Javaでの基本的なプログラミング概念やスキルを身に付けることができます。

クイックツアー[編集]

Javaの基本的な特徴[編集]

Javaは、オブジェクト指向プログラミング言語の中でも特に広く使われています。その特徴を見ていきましょう。

  1. プラットフォーム非依存性
    Javaは、"Write once, run anywhere"(一度書けば、どこでも実行できる)の特性を持ちます。これは、Javaプログラムがプラットフォームに依存しないことを意味します。Windows、Mac、Linux、Androidなど、どのようなオペレーティングシステムでも動作します。
  2. オブジェクト指向プログラミング
    Javaは、クラスとオブジェクトに基づくオブジェクト指向プログラミング言語です。クラスはデータとその操作をカプセル化し、再利用可能なコードのベースとなります。
  3. 静的型付け言語
    Javaは静的型付け言語であり、コンパイル時に型の整合性をチェックします。これにより、実行時の型エラーを事前に検出できます。
  4. ガベージコレクション
    Javaは自動ガベージコレクションを備えています。これは、プログラマーが明示的にメモリ管理を行う必要がなく、不要なオブジェクトが自動的に回収されることを意味します。
  5. 多言語サポート
    Java仮想マシン(JVM)を介して、Javaはさまざまなプログラミング言語をサポートします。これにより、Javaと他の言語との間で相互運用性を確保することができます。
  6. 高度なセキュリティ
    Javaはセキュリティに重点を置いており、Java仮想マシンが実行時にアプリケーションを監視し、悪意のあるコードの実行を防止します。
  7. マルチスレッド
    Javaはマルチスレッドをサポートしており、複数のスレッドを同時に実行できます。これにより、プログラムの効率が向上します。
  8. 例外処理
    Javaは例外処理をサポートしており、予期しないエラーに対処するための機構を提供します。
  9. 高性能
    JavaはJIT(Just-In-Time)コンパイラを使用してコンパイルされたコードを実行し、高速な実行を実現します。また、メモリ管理における最適化も行われています。
  10. 広範なライブラリ
    Javaには豊富な標準ライブラリが用意されており、開発者はこれらのライブラリを活用してアプリケーションを効率的に開発できます。

Javaの基本的な概念と構文[編集]

  1. Javaの基本構造
    Javaプログラムはクラスという単位で構成されます。Javaのクラスは、フィールド(変数)とメソッド(関数)の集まりです。以下は、基本的なJavaクラスの例です。
    HelloWorld.java
    /**
     * HelloWorldクラスは、Javaプログラムの基本的な構造を示し、
     * コンソールに "Hello, World!" というメッセージを出力します。
     */
    public class HelloWorld {
    
        /**
         * mainメソッドは、Javaプログラムのエントリーポイントです。
         * コンソールに "Hello, World!" というメッセージを出力します。
         *
         * @param args コマンドライン引数(このプログラムでは使用しません)。
         */
        public static void main(String[] args) {
            // "Hello, World!" をコンソールに出力する
            System.out.println("Hello, World!");
        }
    }
    
  2. データ型と変数
    Javaにはさまざまなデータ型があります。代表的なものには、int(整数)、double(浮動小数点数)、boolean(真偽値)、String(文字列)などがあります。変数を宣言するには、データ型に続けて変数名を指定します。
    int age = 30;
    double price = 10.5;
    boolean isStudent = true;
    String message = "Hello, Java!";
    
  3. 制御構造
    Javaでは、条件分岐や繰り返し処理を行うための制御構造があります。代表的なものには、if文、whileループ、forループ、拡張forループなどがあります。
    // if文
    int x = 10;
    if (x >= 5) {
        System.out.println("xは5以上です");
    } else {
        System.out.println("xは5未満です");
    }
    
    // whileループ
    int count = 0;
    while (count < 5) {
        System.out.println("カウント: " + count);
        count++;
    }
    
    // forループ
    for (int i = 0; i < 5; i++) {
        System.out.println("iの値は: " + i);
    }
    
    //拡張forループ
    int[] numbers = { 2, 3, 5, 7 }; // 配列の各要素に対して繰り返し処理を行う
    for (int number : numbers) {
        System.out.println(number); 
    }
    
  4. メソッド
    Javaでは、複数の文をまとめて特定の処理を行うメソッドを定義することができます。
    // メソッドの定義
    public static int add(int a, int b) {
        return a + b;
    }
    
    // メソッドの呼び出し
    int result = add(5, 3);
    System.out.println("結果: " + result); // 結果: 8
    
  5. クラスとオブジェクト
    Javaはオブジェクト指向言語です。クラスを定義し、そのクラスから複数のオブジェクトを作成することができます。
    /**
     * Personクラスは、人物の情報を表すクラスです。
     */
    public class Person {
        /**
         * 名前を表す文字列です。
         */
        String name;
        
        /**
         * 年齢を表す整数です。
         */
        int age;
        
        /**
         * Personクラスのコンストラクタです。
         * @param name 名前
         * @param age 年齢
         */
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
        
        /**
         * 人物の情報を表示するメソッドです。
         */
        public void introduce() {
            System.out.println("名前: " + name + ", 年齢: " + age);
        }
    }
    
    // オブジェクトの作成とメソッドの呼び出し
    Person person1 = new Person("太郎", 25);
    person1.introduce(); // 名前: 太郎, 年齢: 25
    

これらはJavaの基本的な概念と構文の一部です。 Javaを学ぶ際には、これらの概念を実際のコードで試してみることが重要です。

ユースケース[編集]

Javaは非常に多様なユースケースで使用されています。以下はその一部です。

  1. Webアプリケーション開発: Javaは、ServletやJSP、Spring Frameworkなどの技術を使用してWebアプリケーションを開発するために広く使用されています。人気のあるフレームワークにはSpring BootやJava EE(Jakarta EE)があります。
  2. モバイルアプリケーション開発: JavaはAndroidアプリケーションの開発に広く使用されています。Android StudioやKotlinと組み合わせて使用されることが一般的です。
  3. デスクトップアプリケーション開発: JavaはSwingやJavaFXなどのGUIライブラリを使用してデスクトップアプリケーションを開発するために使用されます。これにより、クロスプラットフォームのアプリケーションを作成することができます。
  4. サーバーサイド開発: Javaは、大規模なエンタープライズアプリケーションの開発に広く使用されています。Java EE(現在のJakarta EE)やSpring Frameworkなどのフレームワークを使用して、高度なサーバーサイドアプリケーションを構築することができます。
  5. 大規模なデータ処理: Javaは、Apache HadoopやApache Sparkなどのビッグデータ処理フレームワークで使用されています。これらのフレームワークは、大規模なデータセットを処理するためにJavaで実装されています。
  6. 組み込みシステム: Javaは組み込みシステムで使用されることもあります。例えば、AndroidのOS自体はJavaで書かれています。また、組み込みデバイスやIoT(Internet of Things)デバイスでJavaが使用されることもあります。
  7. 金融業界: 金融機関では、トランザクション処理やデータベースアクセスなどの要件を満たすために、Javaが広く使用されています。Javaの安全性、パフォーマンス、信頼性は、金融取引の処理に適しています。

Javaはこれらのユースケースにおいて幅広く活用され、その堅牢性、安全性、クロスプラットフォーム性、豊富なライブラリなどの特徴により、多くの開発者に選択されています。

ベストプラクティス[編集]

Javaのベストプラクティスには、以下のようなものがあります。

  1. 命名規則に従う: クラス名、メソッド名、変数名などは意味のある名前を使い、CamelCaseの命名規則に従うことが推奨されます。
  2. コードの再利用: コードの再利用性を高めるために、継承やコンポジションなどのオブジェクト指向の原則を活用します。また、共通の機能をメソッドやクラスにまとめることも重要です。
  3. コメントを記述する: コードに十分なコメントを付けることで、他の開発者がコードを理解しやすくなります。ただし、コメントはコードを補完するためにあり、適切に保守される必要があります。
  4. 例外処理を行う: 適切な例外処理を行うことで、プログラムの安定性を確保します。適切な例外クラスを選択し、適切なハンドリングを行います。
  5. メモリ管理: Javaは自動ガベージコレクションを備えていますが、メモリリークを避けるためにはメモリの使用を最小限に抑えるように心がけます。
  6. 効率的なデータ構造の選択: 適切なデータ構造を選択することで、アプリケーションのパフォーマンスを向上させることができます。例えば、リスト、セット、マップなどを適切に使用します。
  7. テストを行う: 単体テスト、統合テスト、およびシステムテストを適切に行うことで、プログラムの品質を確保します。JUnitなどのテスティングフレームワークを使用して自動化されたテストを実施します。
  8. バージョン管理: ソースコードのバージョン管理を行うことで、複数の開発者が同時に作業でき、コードの変更履歴を追跡できます。Gitなどのバージョン管理システムを使用します。

これらのベストプラクティスを遵守することで、より堅牢でメンテナブルなJavaプログラムを開発することができます。

イディオム[編集]

Javaのイディオム(慣用句)には、次のようなものがあります。

  1. JavaBeansパターン: JavaBeansは、プレーンなJavaクラスであり、特定のルールに従って命名されたプロパティを持つことが特徴です。これにより、JavaBeansはデータの保持と操作に使用されます。
  2. Builderパターン: Builderパターンは、オブジェクトの生成過程をカプセル化し、柔軟性を提供するデザインパターンです。このパターンを使用すると、複雑なオブジェクトを構築する際にコンストラクタのパラメータ数を減らすことができます。
  3. ファクトリーメソッド: ファクトリーメソッドは、オブジェクトの生成をサブクラスに委任するパターンです。これにより、生成するオブジェクトの型をサブクラスによって決定することができます。
  4. シングルトンパターン: シングルトンパターンは、特定のクラスのインスタンスがアプリケーション全体で一意であることを保証するデザインパターンです。これにより、アプリケーション内の特定のリソースへの一貫したアクセスが可能になります。
  5. ストラテジーパターン: ストラテジーパターンは、アルゴリズムをカプセル化し、実行時に交換可能にするデザインパターンです。これにより、アルゴリズムの実装を柔軟に変更できます。
  6. イテレーターパターン: イテレーターパターンは、コレクション内の要素に順次アクセスするためのデザインパターンです。これにより、コレクション内の要素に対する反復処理を抽象化し、クライアントコードを簡素化します。

これらのイディオムは、Javaのプログラミングスタイルやデザインパターンにおいてよく使用されます。 それぞれが特定の問題を解決するために設計されており、Java開発者が効果的にコードを記述するための重要なツールとなっています。

Hello World![編集]

「Hello World!」は、プログラミングの世界で伝統的に使われる初心者向けの最初のプログラムです。 Javaでも同様に、「Hello World!」プログラムは、基本的な構文や開発環境の設定を理解するために使われます。

ソースコードの書き方[編集]

まず、テキストエディタや統合開発環境(IDE)を使用して、Javaのソースコードを書きます。

以下が「Hello World」のソースコード例です。

HelloWorld.java
public class HelloWorld {
    public static void main(String[] args){
        System.out.println("Hello, world.");
    }
}

このコードでは、HelloWorldという名前のクラスを定義し、その中にmainメソッドを記述しています。 mainメソッドはJavaプログラムのエントリポイントであり、プログラムの実行が開始される場所です。System.out.printlnは、コンソールに文字列を出力するためのメソッドです。

コンパイル[編集]

Javaのソースコードをコンパイルするには、Java Development Kit(JDK)がインストールされている必要があります。 コンパイルは次の手順で行います。

  1. 以下のコマンドを入力して、ソースコードをコンパイルします。
    javac HelloWorld.java
    

これにより、HelloWorld.javaファイルがHelloWorld.classという名前のバイトコードファイルにコンパイルされます。

実行[編集]

コンパイルされたJavaプログラムを実行するには、以下の手順を実行します。

  1. 以下のコマンドを入力して、Javaプログラムを実行します。
    java HelloWorld
    

これにより、コンソールに Hello, World! という文字列が表示されます。

以上が、Javaでの「Hello World」プログラムの作成、コンパイル、実行の手順です。


Javaでの「Hello World」プログラムは、単純な文字列の表示に過ぎませんが、その背後にはいくつかの興味深い蘊蓄があります。

  1. クラスとメソッドの構造: Javaでは、全てのコードがクラスの中に存在します。そして、実行可能なJavaプログラムは、必ずmainメソッドを持つクラスから始まります。これは、Java仕様で定義されています。
  2. プラットフォームの移植性: Javaは、プラットフォームに依存しないという特徴があります。つまり、Javaで書かれたプログラムは、Java仮想マシン(JVM)上で実行されるため、どのオペレーティングシステムでも動作します。これは、Javaが初めて登場したときからの重要な利点であり、広範囲なデバイスやシステムでの使用を可能にしました。
  3. コンパイルと実行の分離: Javaプログラムは通常、ソースコードをコンパイルしてバイトコードに変換し、その後JVMで実行します。この2段階のプロセスにより、Javaは柔軟性とセキュリティを提供します。コンパイルされたバイトコードは、様々な環境で安全に実行されます。
  4. オブジェクト指向プログラミングの導入: Javaはオブジェクト指向プログラミング言語として設計されています。そのため、「Hello World」プログラムでも、クラスとメソッドの構造が強調されています。オブジェクト指向の原則に基づいて設計されたJavaプログラムは、柔軟性がありメンテナンス性が高くなります。
  5. 豊富な標準ライブラリ: Javaには、開発者が利用できる豊富な標準ライブラリが用意されています。これにより、多くの一般的なタスクを簡単に実装できます。例えば、文字列操作、ファイル入出力、ネットワーク通信などが含まれます。

Javaの「Hello World」プログラムは、単なる最初のステップに過ぎませんが、Java言語の重要な特徴や原則を理解するのに役立ちます。

プログラミングのための準備[編集]

JDK[編集]

Wikipedia
Wikipedia
ウィキペディアJava Development Kitの記事があります。

JDK(Java Development Kit)は、Javaプログラムを開発するためのソフトウェア開発キットです。JDKには、Javaプログラムを作成、コンパイル、実行するために必要なツールやファイルが含まれています。具体的には以下のような要素が含まれます。

  1. Javaコンパイラ(javac): Javaソースコードをバイトコードに変換するためのコンパイラです。Javaコンパイラは、Javaプログラムをコンパイルして実行可能な形式に変換します。
  2. Javaランタイム環境(JRE): Javaプログラムを実行するための実行時環境です。JREには、Java仮想マシン(JVM)やJavaクラスライブラリが含まれています。
  3. デバッグツール: デバッグやトラブルシューティングのためのツールが含まれています。例えば、デバッガやプロファイラなどがあります。
  4. APIドキュメント: JavaプログラミングのためのAPIドキュメントが含まれています。これにより、Javaの標準ライブラリやクラスの使用方法を確認することができます。

JDKを利用することで、Javaプログラマは開発環境を構築し、Javaアプリケーションの開発を行うことができます。JDKは無料で利用でき、Javaプログラムを開発するためには必須のツールです。

javac[編集]

Wikipedia
Wikipedia
ウィキペディアjavacの記事があります。

javacは、Javaコンパイラのコマンドラインツールです。このツールは、Javaソースコードファイル(.java拡張子)をJava仮想マシン(JVM)が理解できるバイトコードファイル(.class拡張子)に変換します。

具体的には、以下のような役割があります:

  1. Javaソースコードのコンパイル: javacは、Javaプログラムをコンパイルしてバイトコードに変換します。このバイトコードはJVM上で実行されるため、プラットフォームやオペレーティングシステムに依存しません。
  2. エラーチェックとデバッグ: javacは、ソースコードに文法エラーや論理エラーがないかをチェックし、必要に応じてエラーメッセージを生成します。これにより、開発者はコードの品質を向上させることができます。
  3. バイトコードの生成: javacは、コンパイルされたJavaソースコードからバイトコードファイルを生成します。このバイトコードは、JVM上で実行されるJavaアプリケーションやアプレットの基盤となります。

通常、Java開発キット(JDK)にはjavacが含まれており、開発者はJavaソースコードをコンパイルして実行可能な形式に変換するためにこのツールを使用します。

JRE[編集]

Wikipedia
Wikipedia
ウィキペディアJava Runtime Environmentの記事があります。

JRE(Java Runtime Environment)は、Javaプログラムを実行するための環境を提供するソフトウェアパッケージです。主な役割は以下の通りです:

  1. Javaアプリケーションの実行: JREにはJava仮想マシン(JVM)が含まれており、Javaプログラムを実行可能な形式に変換します。これにより、Javaアプリケーションは異なるプラットフォームやオペレーティングシステム上で動作します。
  2. Javaクラスライブラリの提供: JREには、Java標準ライブラリが含まれています。これにより、Javaアプリケーションは基本的なデータ構造や機能を利用できます。例えば、文字列処理、ネットワーク通信、ファイル操作などが含まれます。
  3. セキュリティ機能の提供: JREは、Javaアプリケーションの実行中にセキュリティを確保し、悪意ある操作やリソースの不正使用を防ぎます。これには、セキュリティマネージャーなどが含まれます。

JREは通常、Java開発キット(JDK)の一部として提供されますが、単体でもJavaアプリケーションの実行に必要なコンポーネントを提供します。

Java仮想マシン[編集]

Wikipedia
Wikipedia
ウィキペディアJava仮想マシンの記事があります。

Java仮想マシン(Java Virtual Machine、JVM)は、Javaプログラムを実行するための仮想的なコンピュータ環境です。JVMは、Javaバイトコード(.classファイル)をホストプラットフォームのネイティブマシンコードに変換し、実行します。

以下はJVMの主な役割です:

  1. プログラムの実行: JVMはJavaバイトコードを解釈し、ネイティブマシンコードに変換して実行します。これにより、Javaプログラムはホストプラットフォームやオペレーティングシステムに依存せずに実行できます。
  2. メモリ管理: JVMはメモリの割り当てや解放を管理し、ガベージコレクションと呼ばれるメカニズムを使用して不要なオブジェクトを自動的に解放します。これにより、メモリリークや無効なメモリアクセスなどの問題を回避できます。
  3. セキュリティ: JVMは、セキュリティ管理を強化するための機能を提供します。例えば、セキュリティマネージャーを使用して、Javaアプリケーションのアクセス権を制御することができます。
  4. 例外処理: JVMは、Javaプログラム内で発生する例外をキャッチし、適切な例外処理を行います。これにより、プログラムの安定性が向上し、予期せぬエラーに対処できます。

JVMはJavaプラットフォームの中核的なコンポーネントであり、Javaのクロスプラットフォーム性やポータビリティ、セキュリティ性を実現するために重要な役割を果たしています。

Oracle JDKとOpen JDK[編集]

Oracle JDK[編集]

Oracle JDKは、Javaプログラミング言語の開発および実行環境を提供するOracle Corporationによる製品です。最新のバージョンではNFTC(No-Fee Terms and Conditions)ライセンスが導入され、商用利用や生産環境での使用も含めて無料で利用できるようになりました。

Open JDK[編集]

OpenJDKは、Javaプログラミング言語のオープンソースのリファレンス実装です。主にGNU General Public License (GPL) の下で提供され、商用利用も含めて無料で利用できます。Oracle JDKのベースとなるソースコードを提供し、多くのLinuxディストリビューションや他のオープンソースプロジェクトで採用されています。

ライセンスの違い[編集]

Oracle JDKとOpenJDKの主なライセンスの違いは以下の通りです:

Oracle JDK
Oracle JDKはOracle Corporationによって提供される有償のJava開発キットであり、商用利用や商用環境でのデプロイメントには有償のサポート契約が必要です。Oracle JDK 17およびそれ以降のリリースではNFTC(No-Fee Terms and Conditions)ライセンスが導入され、商用利用や生産環境での使用も含めて無料で利用できるようになりました。ただし、Oracle JDKには商標やプロプライエタリなコードが含まれる場合があります。
OpenJDK
OpenJDKはオープンソースであり、主にGPL(GNU General Public License)やLGPL(GNU Lesser General Public License)の下で提供されます。商用利用や非商用利用を問わず、すべてのユーザーに無料で利用可能です。商標やプロプライエタリなコードは含まれません。

このように、Oracle JDKとOpenJDKのライセンスの違いは、商用利用に関連する条件と、商標やプロプライエタリなコードの有無にあります。

その他の JDK[編集]

その他のJDK(Java Development Kit)としては、主に以下のようなものがあります:

Amazon Corretto
Amazonが提供する無償で、長期サポートが提供されるOpenJDKの配布版です。

Oracle JDKとの互換性があり、セキュリティアップデートやバグ修正が定期的に提供されます。

AdoptOpenJDK
コミュニティによって維持されているプロジェクトで、無償で提供されるOpenJDKのバイナリ配布版です。
多くのプラットフォーム(Windows、Linux、macOSなど)に対応し、多様なバージョンやビルドが提供されています。
Azul Zulu
Azul Systemsが提供するOpenJDKの実装で、無償版と有償版が提供されています。
無償版は無償で提供され、有償版には追加機能やサポートが含まれます。

これらのJDKは、Javaアプリケーションの開発や実行環境を構築するために使用されます。各JDKには独自の特徴や提供されるサービスがありますので、プロジェクトの要件や目的に応じて適切なものを選択する必要があります。

Java SE LTS[編集]

Java SE LTS(Java Standard Edition Long-Term Support)は、Java SEプラットフォームの長期サポートを提供するプログラムです。Java SE LTSは、特定のJava SEバージョンに対して数年にわたってメンテナンスやセキュリティアップデートを提供し、企業や開発者が安定したプラットフォームを利用し、アプリケーションの長期間の稼働を保証することを目的としています。

Java SE LTSの特徴は以下の通りです:

  1. 長期サポート: Java SE LTSバージョンは、リリース後数年間にわたってメンテナンスとセキュリティアップデートが提供されます。これにより、企業や開発者は安定したプラットフォームを利用し、アプリケーションの長期間の安定した稼働を保証することができます。
  2. 互換性の維持: Java SE LTSバージョンは、互換性の維持が重視されます。新しい機能やAPIは少なくなり、既存のアプリケーションがスムーズに移行できるように設計されます。
  3. エンタープライズ向け: Java SE LTSは、特にエンタープライズ環境での使用を想定しています。エンタープライズアプリケーションは通常、長期間にわたって稼働し、安定性とセキュリティが重要です。Java SE LTSは、この要求を満たすために設計されています。

Java SE LTSプログラムは、企業や開発者が信頼できるプラットフォームを利用し、アプリケーションの開発と運用を容易にすることを目的としています。常に最新の機能を求めるよりも、安定性と互換性を重視する場合には、Java SE LTSバージョンの選択が推奨されます。

2024年2月現在、最新のJava SE LTSはJava 21です。Java 21は2023年9月にリリースされ、LTS(Long-Term Support)バージョンとして提供されました。このバージョンは長期間のサポートを受ける予定であり、セキュリティアップデートやバグ修正が提供されます。企業や開発者は、Java 21を安定したプロダクション環境で使用することができます。

以下は、Java SE LTS(Java Standard Edition Long-Term Support)バージョンの一覧です:

Java SE LTSのバージョン一覧
Java バージョン リリース日 LTS サポート終了日
Java SE 8 LTS 2014年3月18日 2020年12月
Java SE 11 LTS 2018年9月25日 2022年9月
Java SE 17 LTS 2021年9月14日 2026年9月
Java SE 21 LTS 2023年9月19日 2031年9月

Oracle JDKのインストール[編集]

JDK(Java Development Kit)をインストールする手順を以下に詳しく説明します。 これに従って、JDKをインストールしてJavaプログラミングを始めましょう。

  1. JDKのダウンロード:
    まず、Oracleの公式ウェブサイトからJDKをダウンロードします。
    ウェブブラウザを開き、OracleのJDKダウンロードページにアクセスします。次のURLにアクセスしてください:Oracle Java SE Development Kitダウンロード・ページ
    ダウンロードページで、使用しているオペレーティングシステム(Windows、Mac、Linuxなど)に対応したJDKのバージョンを選択します。最新の安定版を選ぶことをおすすめします。
    利用規約に同意し、「ダウンロード」ボタンをクリックします。
  2. JDKのインストール:
    ダウンロードが完了したら、ダウンロードしたファイルを開いてインストールを開始します。
    Windowsの場合
    ダウンロードした.exeファイルを実行します。インストールウィザードが表示されるので、指示に従って進めてください。インストール中にパスやその他のオプションを設定する必要がある場合があります。
    Macの場合
    ダウンロードした.dmgファイルをダブルクリックしてマウントします。マウントされたディスクイメージ内の.pkgファイルを実行して、インストールを開始します。インストール中に管理者パスワードを入力する必要があります。
    GNU/Linuxの場合
    ダウンロードした.tar.gzファイルを解凍します。解凍後、解凍されたディレクトリに移動し、インストールスクリプトを実行します。スクリプトの実行中にsudo権限が必要な場合があります。
    GNU/Linuxの場合、各ディストリビューションのパッケージマネージャを使ってインストールする方法もあります。
  3. 環境変数の設定 (Windowsの場合):
    Windowsの場合、JDKのインストールパスを環境変数に追加する必要があります。
    インストールしたJDKのディレクトリパスをコピーします。通常、デフォルトでは「C:\Program Files\Java\jdk-バージョン」となります。
    コントロールパネルを開き、システムとセキュリティ > システム > システムの詳細設定 > 環境変数 の順に進みます。
    「システム環境変数」のセクションで、"Path" を選択して編集をクリックします。
    新しいウィンドウで、環境変数の一覧が表示されます。ここで、「新規」をクリックし、JDKのインストールパスを追加します。
    追加した後、すべてのウィンドウを閉じて設定を保存します。
    これで、JDKのインストールが完了しました!Javaプログラミングを始める準備が整いました。

プログラミングに必要なもの[編集]

プログラミングには、JDKだけでなく、ソースコードを書くためのテキストエディタが必要です。Windowsではメモ帳、Mac OS Xではテキストエディットなど、基本的なテキストエディタでもプログラミングを始めることができます。 しかし、プログラマは自分の好みや作業効率に合ったエディタを使用することが一般的です。

以下は、いくつかの人気のあるテキストエディタです:

  1. Visual Studio Code: Microsoftが提供する無料のオープンソースのテキストエディタであり、豊富な拡張機能とカスタマイズ性が特徴です。様々なプログラミング言語に対応しています。
  2. Atom: GitHubが提供する無料のオープンソースのテキストエディタであり、高度なカスタマイズ性と拡張機能が充実しています。GitやGitHubとの統合も強力です。
  3. Sublime Text: シンプルで高速なテキストエディタであり、豊富な拡張機能やカスタマイズ性があります。多くのプログラマに愛用されています。
  4. Emacs: フリーソフトウェア財団(FSF)が提供するテキストエディタであり、プログラマブルな特徴があります。拡張性が高く、さまざまなプログラミング言語に対応しています。
  5. Vim: Viエディタの拡張版であり、キーバインドを用いた効率的な操作が特徴です。プラグインやスクリプト機能によって機能を拡張することができます。

これらのテキストエディタは、プログラマの好みや作業スタイルに合わせて選択することができます。自分に合ったエディタを見つけて、快適なプログラミング環境を構築しましょう。

統合開発環境[編集]

統合開発環境(Integrated Development Environment、IDE)は、ソフトウェア開発において、開発者がプログラミング言語の記述、デバッグ、テスト、ビルドなどの作業を行うための統合されたツールセットです。IDEは、開発プロセス全体を支援し、開発者がプロジェクトを効率的に管理できるように設計されています。

統合開発環境の主な特徴は以下の通りです:

  1. コードエディタ: IDEには、ソースコードを編集するためのコードエディタが含まれています。コードエディタは、シンタックスハイライト、自動補完、コードの折り畳みなどの機能を提供し、開発者がコードを効率的に書くことができます。
  2. ビルドツール: IDEには、プロジェクトをビルドするためのビルドツールが統合されています。ビルドツールは、ソースコードをコンパイルし、実行可能なアプリケーションやライブラリを生成します。
  3. デバッグ支援: IDEには、デバッグ機能が組み込まれており、コードの実行中に変数の値を確認したり、ステップ実行したりすることができます。デバッグ支援機能は、バグの特定や修正を容易にします。
  4. バージョン管理: IDEには、ソースコードのバージョン管理を行うためのツールが統合されています。バージョン管理ツールを使用することで、プロジェクトの変更履歴を管理し、チームでの共同作業を支援します。
  5. プロジェクト管理: IDEには、プロジェクトの管理やファイルの整理を行うためのツールが含まれています。プロジェクト管理機能は、プロジェクトの構造を視覚化し、作業の効率化を図ります。
  6. CI(Continuous Integration): IDEには、コードの変更が行われるたびに自動的にビルドやテストを実行する機能が含まれることがあります。これにより、開発者は定期的なビルドとテストを手動で行う必要がなくなり、コードの品質を継続的に確保することができます。
  7. CD(Continuous Deployment): IDEには、ビルドやテストが成功した場合に自動的にデプロイメントを行う機能が含まれることがあります。これにより、ソフトウェアのリリースプロセスを自動化し、迅速なリリースを実現することができます。
  8. 自動化スクリプトの作成: IDE内でCI/CDパイプラインのための自動化スクリプト(例:JenkinsfileやGitHub Actionsのワークフロー)を作成・編集する機能が提供されることがあります。これにより、開発者はCI/CDプロセスを柔軟にカスタマイズできます。
  9. 拡張機能: IDEには、ユーザーが独自の機能やツールを追加できる拡張機能が提供されています。これにより、IDEをカスタマイズして特定の開発環境に合わせることができます。

統合開発環境は、プログラミング作業を効率化し、開発者が生産性を向上させるための強力なツールです。異なるプログラミング言語やフレームワークに対応した多くのIDEが存在し、開発者はプロジェクトの要件や個々の好みに応じて適切なIDEを選択します。

Javaでよく使われるビルドツール[編集]

Javaでよく使われるビルドツールには、以下のようなものがあります:

  1. Apache Maven: Apache Mavenは、Javaプロジェクトのビルド、依存関係管理、テストの実行、デプロイメントなどのタスクを自動化するためのツールです。XML形式のプロジェクト記述ファイル(pom.xml)を使用してプロジェクトの構成を定義し、標準的なビルドライフサイクルを提供します。
  2. Gradle: Gradleは、柔軟性とパフォーマンスを重視したビルドツールです。Groovy DSL(Domain-Specific Language)を使用してビルドスクリプトを記述し、プロジェクトのビルド、テスト、デプロイメントなどのタスクを実行します。Gradleは、Mavenよりも柔軟なビルド定義と依存関係管理を提供し、大規模なプロジェクトに適しています。
  3. Ant: Apache Antは、Javaプロジェクトのビルドとデプロイメントを自動化するためのビルドツールです。XML形式のビルドファイルを使用してビルドタスクを定義し、タスク間の依存関係を指定します。Antは、カスタムタスクやプラグインの追加が容易であり、柔軟性が高い特徴を持ちます。

これらのビルドツールは、Javaプロジェクトのビルドプロセスを効率化し、開発者が効果的にコードのビルド、テスト、デプロイメントを管理するのに役立ちます。それぞれのビルドツールには特有の機能や利点がありますので、プロジェクトの要件やチームの好みに応じて選択することが重要です。

変数と代入[編集]

変数[編集]

プログラミングにおける変数は、値やデータを格納するための記号的な名前です。変数は、メモリ内の特定の場所を参照し、その場所に値を保持します。これにより、プログラム内でデータを操作したり処理したりすることができます。

変数は、プログラム内で使用されるデータの値を表現し、名前を介してそれらの値にアクセスする手段を提供します。また、変数は値を保持するだけでなく、値を変更することもできます。これにより、プログラムが動的に振る舞うことが可能になります。

例えば、プログラムがユーザーの名前や年齢などの情報を取得し、それを後で使用する必要がある場合、変数を使用してその情報を格納し、必要に応じて変更や処理を行うことができます。

Javaにおける変数[編集]

Javaにおける変数とは、データを格納する箱のようなものです。変数は、プログラム内で使用されるデータを保持し、それに名前を付けることができます。これにより、プログラム内で値を簡単に参照したり変更したりできます。

Javaでは、変数を使用する前に、その変数の型(データの種類)を宣言する必要があります。例えば、整数を格納する変数の場合はint型、小数を格納する変数の場合はdouble型、文字列を格納する変数の場合はString型などがあります。

宣言[編集]

変数の宣言は次のように行います:

// 整数を格納する変数の宣言
int age;

// 小数を格納する変数の宣言
double height;

// 文字列を格納する変数の宣言
String name;

これにより、ageheightnameという名前の変数が宣言されます。ただし、この時点ではまだ値は割り当てられていません。

代入[編集]

変数に値を代入するには、以下のようにします:

age = 25;
height = 1.75;
name = "Alice";

これにより、それぞれの変数に値が割り当てられます。

初期化[編集]

また、変数の宣言と初期化を同時に行うこともできます:

int age = 25;
double height = 1.75;
String name = "Alice";

これにより、変数の宣言と初期化を一度に行うことができます。

再代入[編集]

Javaにおいて、再代入とは変数に新しい値を割り当てることを指します。Javaでは、再代入が可能な変数は、その型がプリミティブ型であるか、または参照型であるかによって挙動が異なります。

  1. プリミティブ型の変数の再代入: プリミティブ型の変数は、その型に対応する値を直接保持します。再代入すると、変数が新しい値に更新されます。
    int x = 5; // int型の変数xに初期値5を代入
    x = 10;    // xに新しい値10を再代入
    
  2. 参照型の変数の再代入: 参照型の変数は、オブジェクトへの参照を保持します。再代入すると、変数が新しいオブジェクトへの参照に更新されますが、元のオブジェクトは影響を受けません。
    String str1 = "Hello"; // String型の変数str1に文字列"Hello"を代入
    str1 = "World";        // str1に新しい文字列"World"を再代入
    

変数に再代入された値の型は、変数が宣言された際に指定された型と一致する必要があります。たとえば、int型の変数には整数値を、double型の変数には浮動小数点数を再代入する必要があります。再代入された値の型が異なる場合、コンパイルエラーが発生します。

文字列[編集]

Javaにおける文字列は、文字のシーケンスを表現するためのデータ型です。Javaでは、文字列はjava.lang.Stringクラスを使用して表現されます。文字列は、ダブルクォーテーション(”)で囲まれた文字のシーケンスとして表現されます。

文字列はイミュータブル(変更不能)であり、一度作成されると変更することができません。つまり、文字列を変更する操作は、新しい文字列を作成することになります。

以下は、Javaで文字列を宣言する例です:

String greeting = "Hello, world!";

この例では、greetingという名前の変数に文字列"Hello, world!"が代入されています。

final 修飾された変数[編集]

Javaでは、final修飾子を使って宣言された変数は、イミュータブル(不変)です。final修飾子を使用すると、その変数に対する再代入ができなくなります。つまり、一度初期化された後はその値を変更することができません。

以下は、final修飾子を使って宣言されたイミュータブルな変数の例です:

final int AGE = 30;
final String NAME = "John";

これらの変数AGENAMEは、一度初期化された後に再代入することができません。このような変数は、プログラム内で定数として使用されることがあります。

final 修飾された参照型変数[編集]

Javaにおいて、final修飾された参照型変数は、変数の参照先(オブジェクトへの参照)が不変であることを示します。つまり、一度初期化された後は、その変数が参照するオブジェクトを変更することはできませんが、オブジェクト自体の内容は変更可能です。

以下は、final修飾子を使って宣言された参照型変数の例です:

final StringBuilder builder = new StringBuilder("Hello");

builder.append(", world!"); // オブジェクトの内容を変更する操作

System.out.println(builder.toString()); // 出力: Hello, world!

この例では、final修飾子が付けられたbuilder変数は、一度StringBuilderオブジェクトに初期化された後、その参照先を変更することができません。ただし、StringBuilderオブジェクト自体の内容を変更することは可能です。

キャスト[編集]

Javaにおけるキャスト(cast)は、データ型を変換する操作を指します。Javaでは、異なるデータ型の間で変換を行う際にキャストを使用します。キャストは、変換元のデータ型を指定し、変換後のデータ型に変換するための演算子です。

キャストは基本的に2つの形式があります:

  1. 明示的なキャスト(Explicit cast): 明示的なキャストは、変換元のデータ型を指定して行われます。キャストの前に、変換先のデータ型を括弧で囲んで指定します。
    double d = 10.5;
    int i = (int) d; // 明示的なキャスト
    
    この例では、double型の変数dint型の変数iに明示的にキャストしています。このキャストにより、dの小数部分が切り捨てられてiには整数部分のみが格納されます。
  2. 暗黙的なキャスト(Implicit cast): 暗黙的なキャストは、Javaの型変換ルールに従って、自動的に行われます。暗黙的なキャストは、より小さいデータ型からより大きいデータ型への変換に使用されます。
    int i = 10;
    double d = i; // 暗黙的なキャスト
    
    この例では、int型の変数idouble型の変数dに代入される際に、暗黙的なキャストが行われます。Javaはint型からdouble型への変換を自動的に行い、iの値をdに代入します。

キャストを行う際には、変換元のデータ型と変換後のデータ型が互換性があるかどうかを確認する必要があります。 たとえば、数値型同士のキャストや、参照型の継承関係に基づくキャストが可能ですが、互換性のない型同士のキャストはコンパイルエラーを引き起こします。

型推論 (var)[編集]

Java 10以降、Javaにはローカル変数の型推論機能が追加されました。これは、varキーワードを使用して変数を宣言する際に、コンパイラが変数の型を自動的に推論する機能です。この機能により、変数の型を明示的に指定する必要がなくなり、コードの冗長性を減らすことができます。

変数の宣言時に初期化子が提供される場合、その初期化子の型に基づいて変数の型が推論されます。推論された型は静的な型であり、実行時に変更されることはありません。

例えば、以下のようにvarを使用して変数を宣言することができます:

var i = 1;

varを使用することで、変数の型が明確になる場合には冗長な型の記述を省略できます。ただし、可読性を損なわない範囲での使用が推奨されます。また、varを使用する場合でも、適切な変数名やコメントを追加することで、コードの理解を助けることが重要です。

ループ変数[編集]

Java 10以降、Javaにはループ変数の型推論機能が追加されました。 これにより、forループや拡張forループ(拡張for文、拡張forループ)で、ループ変数の型を自動的に推論することができます。 これにより、コードの冗長性を減らし、可読性を向上させることができます。

具体的には、forループの初期化部でループ変数を宣言し、その型をvarキーワードで指定することができます。 この際、初期化式によって型が明示的に指定される場合、その型を推論してループ変数の型を決定します。

拡張forループでは、コレクションや配列を反復処理する際に、ループ変数の型を指定せずに、varキーワードを使用してループ変数を宣言することができます。この場合、コレクションや配列の要素の型がループ変数の型として推論されます。

以下は、forループと拡張forループでのループ変数の型推論の例です:

// forループでの型推論
for (var i = 0; i < 5; i++) {
    System.out.println(i); // iの型はintと推論される
}

// 拡張forループでの型推論
List<String> strings = List.of("foo", "bar", "baz");
for (var str : strings) {
    System.out.println(str); // strの型はStringと推論される
}

varを使用することで、ループ変数の型を省略し、コードをよりシンプルにすることができます。ただし、適切な変数名やコメントを追加して、コードの可読性を確保することが重要です。

ラムダ式[編集]

ラムダ式の型推論とは、Javaでラムダ式を使用する際に、コンパイラがラムダ式のパラメータの型や戻り値の型を自動的に推論する機能を指します。つまり、ラムダ式のパラメータや戻り値の型を明示的に指定せずに、コンパイラがコードの文脈から型を推測することができます。

var x = (int i) -> i * i;

例えば、次のコードでは、ラムダ式 (int i) -> i * i のパラメータ i の型が int として指定されています。しかし、Javaのコンパイラは、このコードの文脈から i の型が int 型であることを推論することができます。

var キーワードを使用することで、変数 x の型を明示的に指定せずに、コンパイラがラムダ式の型を推論することができます。そのため、コードをよりシンプルに記述することができます。

varキーワードを使わずに、ラムダ式の型を明示的に指定する場合は、次のようになります:

IntUnaryOperator x = (int i) -> i * i;

このコードでは、IntUnaryOperatorインターフェースを使用してラムダ式を宣言しています。IntUnaryOperatorは、int型の引数を受け取り、int型の値を返す関数型インターフェースです。ラムダ式の引数がint型であるため、このインターフェースを使ってラムダ式を宣言しています。

IntUnaryOperatorインターフェース
IntUnaryOperator インターフェースは、Javaの標準ライブラリである java.util.function パッケージに含まれています。このパッケージは、関数型プログラミングをサポートするためのインターフェースやクラスが定義されています。
IntUnaryOperator インターフェースは、引数として整数型を受け取り、整数型の値を返す関数型インターフェースです。具体的には、int applyAsInt(int operand) メソッドを持ちます。これにより、整数型の引数を受け取り、整数型の結果を返す関数を表現することができます。
Javaの関数型インターフェースは、java.util.function パッケージに含まれているため、import java.util.function.IntUnaryOperator; を使用してインポートすることで利用することができます。

varによるラムダ式の型推論をつかうと、この調べごとをする必要がなくなります。

複雑な型推論[編集]

複雑な型を返すメソッドを受け取る場合にも、型推論は有用です。以下の例では、flatMap() メソッドを使用して、文字列のリストを1つの文字列に変換しています。

List<String> list = Arrays.asList("hello", "world");
var result = list.stream()
        .flatMap(s -> Arrays.stream(s.split("")))
        .collect(Collectors.joining());

最後に、ループを用いた具体例を示します。以下の例では、リストを String[] に変換しています。

List<String> list = Arrays.asList("hello", "world");
var array = new String[list.size()];
var index = 0;
for (var element : list) {
    array[index++] = element;
}

附録[編集]

チートシート[編集]

public class Main {
    public static void main(String[] args) {
        // 変数の宣言と初期化
        int num1 = 10;
        int num2 = 20;
        String name = "John";
        boolean flag = true;
        
        // 変数の使用と演算
        System.out.println("num1 + num2 = " + (num1 + num2)); // 30
        System.out.println("My name is " + name); // My name is John
        System.out.println("flag is " + flag); // flag is true
        
        // プリミティブ型と参照型
        int[] array = {1, 2, 3}; // 参照型の例
        char ch = 'a'; // プリミティブ型の例
        
        // プリミティブ型と参照型の違い
        int num3 = num1; // num1の値をコピーしてnum3に代入(値渡し)
        int[] array2 = array; // arrayの参照をコピーしてarray2に代入(参照渡し)
        array[0] = 100; // arrayの値を変更
        
        System.out.println("num3 = " + num3); // num3 = 10
        System.out.println("array[0] = " + array[0]); // array[0] = 100
        System.out.println("array2[0] = " + array2[0]); // array2[0] = 100
        
        // プリミティブ型と参照型の比較
        boolean isEqual = num1 == num3; // プリミティブ型同士の比較
        boolean isSameArray = array == array2; // 参照型同士の比較
        
        System.out.println("num1 == num3 : " + isEqual); // num1 == num3 : true
        System.out.println("array == array2 : " + isSameArray); // array == array2 : true
    }
}

用語集[編集]

  1. 変数 (Variable): プログラミングにおける変数は、値やデータを格納するための記号的な名前です。プログラム内でデータを操作したり処理したりする際に使用されます。
  2. 宣言 (Declaration): 変数の宣言とは、変数をプログラム内で使用する準備をすることです。変数の型と名前を指定して、コンピュータにその変数を識別するための領域を割り当てます。
  3. 代入 (Assignment): 代入とは、変数に値を格納する操作です。変数に値を代入することで、その変数がその値を保持することができます。
  4. 初期化 (Initialization): 初期化とは、変数に初期値を設定する操作です。変数を宣言と同時に初期値を設定することで、その変数が宣言された時点で値を持つことができます。
  5. 再代入 (Reassignment): 再代入とは、変数に新しい値を割り当てる操作です。変数には、同じ型の新しい値を代入することができます。
  6. イミュータブル (Immutable): イミュータブルとは、変更不可能なことを指します。Javaでは、final修飾子を使用して宣言された変数や、文字列などの一部のオブジェクトはイミュータブルです。
  7. キャスト (Cast): キャストとは、データ型を変換する操作です。Javaでは、異なるデータ型の間で変換を行う際にキャストが使用されます。
  8. 型推論 (Type Inference): 型推論とは、コンパイラがコードの文脈から変数の型を推測する機能です。Java 10以降では、varキーワードを使用して型推論を行うことができます。
  9. ラムダ式 (Lambda Expression): ラムダ式とは、無名関数を表現するための記法です。Javaでは、関数型インターフェースの実装として使用されます。
  10. ループ変数 (Loop Variable): ループ変数とは、forループや拡張forループで使用される反復変数のことを指します。Java 10以降では、ループ変数の型推論機能が追加されました。
  11. 複雑な型推論 (Complex Type Inference): 複雑な型を返すメソッドを受け取る場合にも、型推論が有用です。Javaでは、flatMap()メソッドなどでの複雑な型推論が行われます。

コメント[編集]

プログラミングにおけるコメントは、コード内に追加されるテキストであり、主に以下の目的で使用されます。

  1. 説明とドキュメント化: コードの目的や処理の説明、特定のアルゴリズムや処理の詳細を記述することができます。これにより、他の開発者がコードを理解しやすくなります。
  2. デバッグとトラブルシューティング: コード内で問題が発生した場合、コメントを使用して特定のセクションや変数の目的を理解し、デバッグしやすくすることができます。
  3. コードの一時的な無効化: コードの一部を一時的に無効にするために、コメントを使用することができます。これは、デバッグや特定の機能のテストなど、開発プロセスの一環として役立ちます。

プログラミング言語によってコメントの書き方や形式は異なりますが、一般的な方法として、単一行コメントや複数行コメントがあります。単一行コメントは通常、行の先頭に // を置いて記述します。複数行コメントは、/* で始まり */ で終わるブロックを使用して記述します。

コメントは、コードの可読性やメンテナンス性を向上させる重要な手法であり、良いコメントを記述することは、プログラミングにおける良い実践の一部です。

Javaのコメント[編集]

Javaのコメントは、Javaプログラム内に追加されるテキストであり、コードの読みやすさや理解を助けるために使用されます。コメントはコンパイラによって無視され、プログラムの実行時には無視されます。主な目的は、以下の点にあります。

  1. 説明とドキュメント化: コードの目的や処理の説明、特定のアルゴリズムや処理の詳細を記述することができます。これにより、他の開発者がコードを理解しやすくなります。
  2. デバッグとトラブルシューティング: コード内で問題が発生した場合、コメントを使用して特定のセクションや変数の目的を理解し、デバッグしやすくすることができます。
  3. コードの一時的な無効化: コードの一部を一時的に無効にするために、コメントを使用することができます。これは、デバッグや特定の機能のテストなど、開発プロセスの一環として役立ちます。

Javaでは、以下の2つの主なコメント形式が一般的に使用されます。

  1. 単一行コメント: // を使って行ごとにコメントを追加します。
    // この行は単一行コメントです
    int x = 5; // 変数xを値で初期化する
    
  2. 複数行コメント: /**/ の間に複数の行のコメントを追加します。
    /*
    これは
    複数行コメントです
    */
    int y = 10; /* 変数yを値で初期化する */
    

コメントは、効果的なコードの記述やメンテナンスに欠かせない要素であり、開発プロセスをスムーズにします。

JavaDoc[編集]

JavaDocは、Javaプログラミング言語において、ソースコード内のドキュメンテーションを生成するためのツールです。これは、Javaプログラムのソースコードに特定のコメント形式を記述し、それをJavaDocツールで処理することで、プログラムのAPIドキュメントを生成します。

JavaDocコメントは通常、クラス、メソッド、フィールドなどの要素に対して記述され、特定の形式に従います。一般的には、以下のような形式で記述されます。

/**
 * このクラスは...(クラスの概要)
 * 詳細な説明や使用方法など
 */
public class MyClass {
    /**
     * このメソッドは...(メソッドの概要)
     * 詳細な説明やパラメータ、戻り値など
     * @param param1 パラメータ1の説明
     * @param param2 パラメータ2の説明
     * @return 戻り値の説明
     */
    public int myMethod(int param1, int param2) {
        // メソッドの処理
    }
}

JavaDocコメントには、概要や詳細な説明、パラメータ、戻り値、例などが含まれることがあります。JavaDocコメントを適切に記述することで、他の開発者がAPIを理解しやすくなり、プログラムの使用方法や機能を簡単に把握できるようになります。

式と演算子[編集]

プログラミングにおける式(Expression)は、値や演算子、関数呼び出し、変数などから構成される計算を表す文法構造です。式はプログラム内で評価され、結果の値を生成します。

演算子(Operator)は、式内で値や変数を操作するための記号またはキーワードです。演算子には算術演算子(加算、減算など)、比較演算子(等しい、大なり、小なりなど)、論理演算子(AND、ORなど)、代入演算子(変数に値を代入する演算子)などがあります。演算子は一般的に、式内で値を組み合わせて新しい値を生成するために使用されます。

例えば、以下のような式があります:

a + b * c

この式は、変数 abc の値を使用して、乗算(*)と加算(+)の演算を行います。これにより、新しい値が生成されます。

Javaにおける式と演算子[編集]

Javaにおける式(Expression)は、値、変数、演算子、メソッド呼び出し、またはこれらの組み合わせから構成されるプログラム内の計算を表す文法要素です。式はプログラム内で評価され、結果の値を生成します。

Javaの演算子(Operator)は、式内で値や変数を操作するための特殊な記号またはキーワードです。

Javaの演算子は多岐にわたり、主な種類には以下のようなものがあります:

  1. 算術演算子(Arithmetic Operators): 加算(+)、減算(-)、乗算(*)、除算(/)、剰余(%)など、数値データ型の間で算術演算を実行するための演算子です。
  2. 比較演算子(Comparison Operators): 等しい(==)、等しくない(!=)、大なり(>)、小なり(<)、大なりイコール(>=)、小なりイコール(<=)など、値や式の比較を行うための演算子です。結果は真偽値(trueまたはfalse)となります。
  3. 論理演算子(Logical Operators): 論理積(AND:&&)、論理和(OR:||)、否定(NOT:!)など、真偽値を操作するための演算子です。
  4. ビット演算子(Bitwise operators): 論理積(AND:&)、論理和(OR:|)、排他的論理和(XOR:^)、否定(NOT:~)などの操作を提供し、ビット単位の操作により効率的なデータ処理やビットマスクの作成が可能です。
  5. 代入演算子(Assignment Operators): 代入(=)、加算代入(+=)、減算代入(-=)、乗算代入(*=)など、変数に値を代入するための演算子です。
  6. その他の演算子(Other Operators): インクリメント(++)、デクリメント(--)、条件演算子(条件式 ? 結果1 : 結果2)、ビット演算子(ビット単位の論理演算を行う演算子)など、その他の種類の演算子があります。

これらの演算子を使用して、Javaプログラム内で様々な計算や操作を行うことができます。

算術演算子[編集]

Javaにおける算術演算子は、基本的な数値計算を行うための演算子を指します。 Javaでは、整数型と浮動小数点型のデータを扱うための算術演算子が提供されています。

主な算術演算子には以下が含まれます:

  1. 加算(Addition)
    int sum1 = 5 + 3; // 整数の加算、sum1には8が代入される
    double sum2 = 5.5 + 3.2; // 浮動小数点数の加算、sum2には8.7が代入される
    
  2. 減算(Subtraction)
    int difference1 = 10 - 4; // 整数の減算、difference1には6が代入される
    double difference2 = 10.5 - 4.2; // 浮動小数点数の減算、difference2には6.3が代入される
    
  3. 乗算(Multiplication)
    int product1 = 6 * 2; // 整数の乗算、product1には12が代入される
    double product2 = 3.5 * 2.0; // 浮動小数点数の乗算、product2には7.0が代入される
    
  4. 除算(Division)
    double quotient1 = 10.0 / 3.0; // 浮動小数点数の除算、quotient1には3.3333...が代入される
    double quotient2 = 10 / 3.0; // 整数と浮動小数点数の除算、quotient2には3.3333...が代入される
    
  5. 剰余(Modulus)
    int remainder1 = 10 % 3; // 整数の剰余、remainder1には1が代入される
    double remainder2 = 10.5 % 3.0; // 浮動小数点数の剰余、remainder2には1.5が代入される
    

Javaの算術演算は、整数型と浮動小数点型の両方で動作し、適切な結果を返します。 プログラマは、演算に使用される数値の型を適切に選択する必要があります。

多様な算術演算子[編集]

/**
 * 算術演算子の例
 */
public class Main {

    /**
     * メインメソッド。プログラムのエントリーポイント。
     * 
     * @param args コマンドライン引数
     */
    public static void main(String[] args) {
        int a = 10;
        int b = 3;
        
        System.out.println(a + " + " + b + " = " + (a + b));
        System.out.println(a + " - " + b + " = " + (a - b));
        System.out.println(a + " * " + b + " = " + (a * b));
        System.out.println(a + " / " + b + " = " + (a / b));
        System.out.println(a + " % " + b + " = " + (a % b));

        a = Integer.MAX_VALUE;
        b = 1;
        System.out.println(a + " + " + b + " = " + (a + b) + "\t// オーバーフロー!");

        // ゼロ除算:
        a = 42;
        b = 0;
        try {
            System.out.print(a + " / " + b + " = ");
            System.out.println(a / b);
        } catch (ArithmeticException e) {
            System.out.println("例外捕捉:" + e);
        }
        
        // ゼロ除算:
        try {
            System.out.print(a + " % " + b + " = ");
            System.out.println(a % b);
        } catch (ArithmeticException e) {
            System.out.println("例外捕捉:" + e);
        }
        
        // double型の算術演算
        double x = 10.5;
        double y = 3.2;
        System.out.println(x + " + " + y + " = " + (x + y));
        System.out.println(x + " - " + y + " = " + (x - y));
        System.out.println(x + " * " + y + " = " + (x * y));
        System.out.println(x + " / " + y + " = " + (x / y));
        System.out.println(x + " % " + y + " = " + (x % y));

        y = 0.0;
        System.out.println(x + " / " + y + " = " + (x / y));

        x = 0.0;
        System.out.println(x + " / " + y + " = " + (x / y));
    }
}
実行結果
10 + 3 = 13
10 - 3 = 7
10 * 3 = 30
10 / 3 = 3
10 % 3 = 1
2147483647 + 1 = -2147483648	// オーバーフロー!
42 / 0 = 例外捕捉:java.lang.ArithmeticException: / by zero
42 % 0 = 例外捕捉:java.lang.ArithmeticException: / by zero
10.5 + 3.2 = 13.7
10.5 - 3.2 = 7.3
10.5 * 3.2 = 33.6
10.5 / 3.2 = 3.28125
10.5 % 3.2 = 0.8999999999999995
10.5 / 0.0 = Infinity 
0.0 / 0.0 = NaN

InfinityとNaN[編集]

JavaのInfinityとNaNは、浮動小数点数の特殊な値であり、IEEE 754規格に基づいて定義されています。以下に、それぞれの意味と特性について説明します。

JavaのInfinityとNaNは、浮動小数点数の計算において特殊な値として使用されます。これらの値は、次のような場面で発生します。

  1. Infinity(無限大):
    • 無限大は、有限の数値を0.0で割った場合や、オーバーフローが発生した場合に発生します。
    • 例えば、double result = 5.0 / 0.0;のような式を評価すると、resultの値は無限大になります。
    • 無限大は、有限の数値よりも大きいことが特性として挙げられます。
    • Double.POSITIVE_INFINITYの定数は(正の)無限大を表します。
    • IEEE 754規格では、無限大は指数部が符号が+、最大値でかつ仮数部が0の状態で表されます。
  2. -Infinity(負の無限大):
    • 負の無限大、有限の負の数値を0.0で割った場合や、オーバーフローが発生した場合に発生します。
    • 例えば、double result = 5.0 / -0.0;のような式を評価すると、resultの値は負の無限大になります。
    • 負の無限大は、有限の数値よりも小さいことが特性として挙げられます。
    • Double.NEGATIVE_INFINITYの定数は、負の無限大を表します。
    • IEEE 754規格では、負の無限大は指数部が符号が+、最大値でかつ仮数部が0の状態で表されます。
  3. NaN(非数):
    • NaNは、0を0で割った場合や、0.0を0.0で割った場合、あるいは数学的に不正な演算が行われた場合に発生します。
    • 例えば、double result = Math.sqrt(-1);のような式を評価すると、resultの値はNaNになります。
    • NaNは、数値としての意味を持たないことを示します。
    • Double.NaNという定数があり、これはNaNを表します。
    • NaNは、どの数値とも等しくないため、NaNとの比較は常にfalseになります。
    • IEEE 754規格では、NaNは指数部が最大値でかつ仮数部が0でない状態で表されます。

isNaN()とisFinite()メソッド:

  • Javaでは、DoubleクラスやFloatクラスには、NaNやInfinityを判定するためのメソッドが用意されています。
  • isNaN()メソッドは、引数がNaNかどうかを判定します。NaNの場合はtrueを返し、それ以外の場合はfalseを返します。
  • isFinite()メソッドは、引数が有限の数かどうかを判定します。InfinityやNaNの場合はfalseを返し、それ以外の場合はtrueを返します。

IEEE 754規格に基づいて定義されたこれらの特殊な値は、浮動小数点数の算術演算においてエラー処理や特殊な状況を処理するために使用されます。これらの特性を理解することは、正確な数値計算を行う上で重要です。

-0.0[編集]

-0.0(マイナスゼロ)は、浮動小数点数の一部で、通常のゼロとは異なる概念です。IEEE 754規格では、ゼロを表現する方法として、符号付きゼロ(+0.0および-0.0)が導入されています。

  • +0.0(プラスゼロ): すべてのビットが0で、符号ビットが0。
  • -0.0(マイナスゼロ): すべてのビットが0で、符号ビットが1。

この区別は、通常の算術演算では影響を与えませんが、一部の特殊な状況で重要になります。例えば、次のような場面で符号つきゼロが役立ちます。

  1. ゼロで割った場合:
    • 1.0 / +0.0 は正の無限大になります。
    • 1.0 / -0.0 は負の無限大になります。
  2. 符号を保持する場合:
    • 符号つきゼロは、正確な結果を保持するために使用されます。例えば、正の数から負の数を引くときなどに、結果の符号を正確に反映するために使われます。

JavaのDoubleとFloatのデータ型では、+0.0と-0.0は異なる値として区別されます。これは、JavaがIEEE 754規格に従っているためです。例えば、以下のようなコードを実行すると、+0.0と-0.0が等しいかどうかを確認できます。

System.out.println(0.0 == -0.0); // true
System.out.println(Double.compare(0.0, -0.0)); // 1
System.out.println(Double.compare(0.0, 0.0)); // 0
System.out.println(Double.compare(-0.0, 0.0)); // -1
このコードでは、==演算子によって0.0と-0.0が等しいかどうかを比較しています。
Double.compareメソッドによって比較すると、ゼロの符号の違いを考慮します。

Double.compare() は、Java プログラミング言語において、2 つの double 値を比較するための静的メソッドです。このメソッドは、次のような形式で使用されます:

public static int compare(double d1, double d2)

Double.compare() メソッドは、以下のルールに従って比較を行います。

  • もし d1d2 より小さい場合、負の値が返されます。
  • もし d1d2 より大きい場合、正の値が返されます。
  • もし d1d2 と等しい場合、0 が返されます。

算術演算の注意事項[編集]

桁あふれ[編集]

整数演算の桁あふれ[編集]

整数演算の桁あふれ(オーバーフロー)は、整数の演算結果がそのデータ型で表現可能な範囲を超える場合に発生します。Javaの整数型には、それぞれの範囲が定義されています。以下に、主な整数型とその範囲を示します。

  1. byte: -128 から 127
  2. short: -32,768 から 32,767
  3. int: -2,147,483,648 から 2,147,483,647
  4. long: -9,223,372,036,854,775,808 から 9,223,372,036,854,775,807

たとえば、int型でのオーバーフローが発生する状況を考えてみましょう。以下のコードでは、整数の最大値に1を加えようとしています。

int maxValue = Integer.MAX_VALUE;
int overflow = maxValue + 1;
System.out.println("Overflow: " + overflow);

このコードを実行すると、overflow 変数は -2147483648 になります。これは、Integer.MAX_VALUE で表現される最大値に1を加えることで、オーバーフローが発生し、最小値(Integer.MIN_VALUE)に戻るためです。

同様に、他の整数型でも同様の挙動が発生します。オーバーフローを防ぐためには、適切な範囲内での演算を行うか、オーバーフローが発生する可能性がある場合には適切に処理する必要があります。

Math.addExactと、そのファミリー[編集]

Javaでは、整数演算でオーバーフローを生じても例外は上がりません。 例外をあげオーバーフローを捕捉するために、Math.addExactと、そのファミリーが用意されています。

Math.addExact() メソッドは、Java 8 で追加された整数演算時のオーバーフローを検出するためのメソッドの一部です。このメソッドは、整数型の加算を行い、結果がそのデータ型で表現可能な範囲を超えた場合に ArithmeticException をスローします。

Math クラスには、他にもオーバーフローを検出するためのメソッドが用意されています。主なものには、次のようなものがあります:

  1. Math.addExact(int x, int y):整数値 xy を加算し、オーバーフローが発生した場合は ArithmeticException をスローします。
  2. Math.subtractExact(int x, int y):整数値 x から y を減算し、オーバーフローが発生した場合は ArithmeticException をスローします。
  3. Math.multiplyExact(int x, int y):整数値 xy を乗算し、オーバーフローが発生した場合は ArithmeticException をスローします。
  4. Math.incrementExact(int a):整数値 a をインクリメントし、オーバーフローが発生した場合は ArithmeticException をスローします。
  5. Math.decrementExact(int a):整数値 a をデクリメントし、オーバーフローが発生した場合は ArithmeticException をスローします。

これらのメソッドを使用することで、整数演算時にオーバーフローが発生した場合に、適切に例外を処理できます。

以下は、Math.addExact() メソッドを使用して整数値の加算を行い、オーバーフローが発生した場合に例外を処理する例です。

public class Main {
    public static void main(String[] args) {
        try {
            int result = Math.addExact(Integer.MAX_VALUE, 1);
            System.out.println("Result: " + result);
        } catch (ArithmeticException e) {
            System.out.println("Overflow occurred: " + e.getMessage());
        }
    }
}

このコードでは、Integer.MAX_VALUE に 1 を加算しようとしています。Math.addExact() メソッドは、この加算がオーバーフローを引き起こす可能性があるため、例外をスローします。try-catch ブロックを使用して、ArithmeticException をキャッチし、オーバーフローが発生したことを示すメッセージを出力しています。

浮動小数点演算の桁あふれ[編集]

浮動小数点演算の桁あふれは、浮動小数点数を操作する際に、その値がデータ型で表現可能な範囲を超える場合に発生します。浮動小数点数は、指数部と仮数部から構成され、一定の精度を保ちつつ非常に大きな値や小さな値を表現するために使用されます。

Javaにおいて、浮動小数点数は主に以下の2つのデータ型で表現されます。

  1. float: 単精度浮動小数点数 (32ビット)
  2. double: 倍精度浮動小数点数 (64ビット)

これらのデータ型は、それぞれ一定の範囲と精度を持っていますが、非常に大きな値や小さな値に対しても表現可能です。

桁あふれは、浮動小数点演算の結果が、そのデータ型で表現可能な範囲を超える場合に発生します。これにより、計算結果が無限大や無限小に発散する場合や、精度が失われる場合があります。また、浮動小数点数の演算において、有効桁数を超えた部分が切り捨てられることも桁あふれの一形態です。

例えば、次のコードでは、倍精度浮動小数点数の最大値に1を加える操作を行っています。

double maxValue = Double.MAX_VALUE;
double overflow = maxValue + 1;
System.out.println("Overflow: " + overflow);

この場合、overflow 変数の値は Infinity になります。これは、最大値に1を加えた結果が倍精度浮動小数点数の表現可能な範囲を超えたため、桁あふれが発生したことを示しています。

浮動小数点数と誤差[編集]

Javaの浮動小数点数における誤差は、主に2つの要因によって生じます。

  1. 有効桁数の制限: Javaの浮動小数点数は、IEEE 754標準に基づいて実装されています。float型は32ビットで、有効桁数は約7桁です。double型は64ビットで、有効桁数は約15桁です。そのため、非常に大きな数や非常に小さな数を表現する場合、精度の制限により誤差が生じます。たとえば、10進数で0.1をfloat型やdouble型で表現すると、厳密には0.1ではなく、近似的な値になります。
  2. 丸め誤差と演算誤差: 浮動小数点数の演算においては、丸め誤差や演算誤差が生じることがあります。これは、浮動小数点数を近似的に表現するための有限なビット数で演算を行うために生じるものです。特に、加算や減算、乗算、除算などの演算において、丸め誤差や演算誤差が生じることがあります。これにより、計算結果が厳密な値と異なる場合があります。

Javaの浮動小数点数における誤差を最小限に抑えるためには、次のような注意点があります。

計算の順序を適切に管理し、丸め誤差を最小限に抑える。

  • 必要に応じて、BigDecimalクラスを使用して高精度な計算を行う。
  • 数値計算ライブラリや専門家によって提供される特殊な数値計算手法を使用する。

これらの対策を講じることで、Javaの浮動小数点数による誤差を最小限に抑えることができます。

また、浮動小数点数の演算における丸め誤差や演算誤差を最小限に抑えるためには、以下のような注意点があります。

  1. 適切なデータ型を選択する: 浮動小数点数は精度を失う可能性があるため、必要な精度に合わせてfloat型またはdouble型を選択する必要があります。より高い精度が必要な場合はdouble型を使用しますが、その分メモリ使用量も大きくなります。
  2. 演算の順序を考慮する: 浮動小数点数の演算においては、演算の順序が結果に影響を与える場合があります。たとえば、加算や減算といった基本的な演算から始め、乗算や除算といった複雑な演算を後に行うと、丸め誤差を最小限に抑えることができます。
  3. 比較演算における注意: 浮動小数点数の比較演算は、厳密な等値判定が難しい場合があります。丸め誤差や演算誤差の影響を考慮して、適切な精度で比較演算を行う必要があります。通常は、等値判定ではなく、ある値が別の値よりも大きいか、または小さいかを判定することが推奨されます。
  4. 結果の解釈: 浮動小数点数の演算結果を解釈する際には、その精度や誤差の範囲を理解する必要があります。特に、科学計算や金融取引などの精密な計算においては、計算結果の信頼性を確保するために十分な検証と解釈が必要です。

これらの注意点を考慮することで、Javaの浮動小数点数による計算における誤差を最小限に抑えることができます。

さらに、浮動小数点数の計算における誤差を最小限に抑えるために、次のようなアプローチも考慮されます。

  1. 丸めモードの設定: Javaでは、浮動小数点数の計算における丸めモードを設定することができます。デフォルトでは、丸めモードは「デフォルト」であり、周囲に最も近い数に丸められます。しかし、必要に応じて丸めモードを変更して、計算結果に影響を与えることができます。例えば、丸め誤差を最小限に抑えるために、上向き丸め(ceiling)、下向き丸め(floor)、ゼロから遠い方向の丸め(向上丸め)、ゼロに近い方向の丸め(向下丸め)などの丸めモードを使用することができます。
  2. 有効桁数の管理: 浮動小数点数の計算においては、有効桁数の制限により誤差が生じることがあります。特に、非常に大きな数や非常に小さな数を表現する場合、有効桁数の不足により計算結果に誤差が生じることがあります。そのため、計算に使用する浮動小数点数の有効桁数を適切に管理することが重要です。必要に応じて、BigDecimalなどの精度の高いデータ型を使用して計算を行うことも考慮されます。
  3. ライブラリの活用: 数値計算に関連するライブラリを活用することで、浮動小数点数の計算における誤差を最小限に抑えることができます。これらのライブラリには、高精度な計算を行うための機能や、誤差を最小限に抑えるためのアルゴリズムが含まれています。特に、金融取引や科学計算などの精密な計算を行う場合には、これらのライブラリを活用することが推奨されます。

以上のようなアプローチを組み合わせることで、Javaの浮動小数点数を使用した計算における誤差を最小限に抑えることができます。ただし、特定の問題や要件に応じて、最適なアプローチを選択する必要があります。

0.1を10回足しても1.0にならない![編集]

浮動小数点数の内部表現により、一部の10進数を正確に表現することができません。たとえば、0.1を浮動小数点数として表現すると、厳密な値ではなく近似値になります。そのため、0.1を10回足しても厳密に1.0にはならない場合があります。

Javaでは、float型やdouble型を使用して浮動小数点数を表現しますが、これらの型は有限のビット数で浮動小数点数を表現するため、一部の10進数を正確に表現することができません。その結果、浮動小数点数の計算においては、丸め誤差や演算誤差が生じる可能性があります。

例えば、次のコードを見てみましょう。

double sum = 0.0;
for (int i = 0; i < 10; i++) {
    sum += 0.1;
}
System.out.println(sum); // 出力: 0.9999999999999999

このコードでは、0.1を10回足した結果が正確に1.0にならず、0.9999999999999999 という近似値になります。

このように誤差が生じるのは、内部的に浮動小数点数は2進数で扱われているためです(0.1は、2進数では循環小数になるため正確に表現できません)。

カハンの総和アルゴリズム[編集]

誤差を補正する方法はいくつかありますが、カハンの総和アルゴリズム( Kahan summation algorithm )が代表的です。

カハンの総和アルゴリズム
public class Main {
    public static void main(String[] args) {
        double d = 0.0;
        for (int i = 0; i < 10; i++) d += 0.1;
        System.out.println(d);

        d = 0.0;
        double c = 0.0;
        for (int i = 0; i < 10; i++) {
            double y = 0.1 - c;
            double t = d + y;
            c = ( t - d ) - y;
            d = t;
        }
        System.out.println(d);

        float f = 0.0f;
        for (int i = 0; i < 10; i++) f += 0.1f;
        System.out.println(f);
        
        f = 0.0f;
        float fc = 0.0f;
        for (int i = 0; i < 10; i++) {
            float y = 0.1f - fc;
            float t = f + y;
            fc = ( t - f ) - y;
            f = t;
        }
        System.out.println(f);
    }
}
$ javac Main.java
$ java Main
0.9999999999999999
1.0
1.0000001 
1.0
Java Stream API[編集]

また、Java Stream API も補正アルゴリズムを実装しています。

Stream APIを使った総和
import java.util.stream.DoubleStream;

class Main {
    public static void main(String[] args) {
        // DoubleStream.builder() を使用して、DoubleStream.Builderオブジェクトを作成します。
        // これは、DoubleStreamを構築するためのビルダーオブジェクトです。
        final var builder = DoubleStream.builder();
        
        // ループを10回実行し、builder.add(0.1) を使用して、ビルダーオブジェクトに0.1を追加します。
        // これにより、10回のループを通じて0.1が10回追加されます。
        for (int i = 0; i < 10; i++)
            builder.add(0.1);
        
        // builder.build() を使用して、ビルダーオブジェクトからDoubleStreamオブジェクトを構築します。
        // これにより、10回のループで追加された0.1の値が含まれたDoubleStreamが得られます。
        System.out.println(builder.build().sum());
        
        // sum() メソッドを使用して、DoubleStreamオブジェクトの合計を計算します。
        // これにより、10回のループで追加された0.1の値の合計が計算されます。
        
        // 最後に、計算された合計値が出力されます。
    }
}
1.0
DoubleStreamのメソッドsum()は、保証を行うアルゴリズムを採用しています。

優先順位と結合性[編集]

Javaの算術演算子には、優先順位と結合性があります。以下に、一般的な算術演算子の優先順位と結合性を示します。

乗算 (*) および除算 (/、%): 乗算と除算は、加算と減算よりも高い優先順位を持ちます。また、乗算と除算は左から右に結合します。
加算 (+) および減算 (-): 加算と減算は、乗算と除算と同じ優先順位を持ちます。また、加算と減算も左から右に結合します。

優先順位[編集]

この優先順位と結合性に基づいて、式が評価されます。例えば、次の式を考えてみましょう。

int result = 5 + 3 * 2;

この式では、乗算 (*) が加算 (+) よりも高い優先順位を持つため、まず 3 * 2 が計算されます。結果は 6 です。その後、5 と 6 の加算が行われ、最終的な結果は 11 になります。

結合性[編集]

結合性(associativity)は、演算子が式内で連続して出現する場合に、その演算子がどのような順序で評価されるかを示す性質です。結合性は通常、左から右への結合(左結合性)または右から左への結合(右結合性)のいずれかとして定義されます。

算術演算子の結合性により、この式は左から右に評価されます。例えば、次の式を考えてみましょう。

int result = 10 - 5 - 3;

この式では、減算 (-) は左から右に結合するため、まず左側の 10 - 5 が計算されます。結果は 5 です。その後、5 から 3 を減算することで、最終的な結果は 2 になります。

Javaの算術演算子の優先順位と結合性を理解することで、式を正しく評価することができます。

比較演算子[編集]

Javaの比較演算子は、異なる値や式の間で比較を行い、結果を真偽値(trueまたはfalse)で返します。以下は、Javaで使用される主な比較演算子です。

  1. ==:2つの値が等しいかどうかを比較します。プリミティブ型の場合、値の比較を行います。参照型の場合、オブジェクトの参照が同じかどうかを比較します。
  2. !=:2つの値が等しくないかどうかを比較します。
  3. >:左辺の値が右辺の値より大きいかどうかを比較します。
  4. <:左辺の値が右辺の値より小さいかどうかを比較します。
  5. >=:左辺の値が右辺の値以上かどうかを比較します。
  6. <=:左辺の値が右辺の値以下かどうかを比較します。

これらの比較演算子は、条件文やループ、その他の制御構造でよく使用されます。

論理演算子[編集]

論理演算子は、論理値(真偽値)を操作するために使用されます。Javaでは、3つの主要な論理演算子があります。

  1. &&(AND):論理積演算子は、両側の式がともにtrueの場合にtrueを返します。片方でもfalseであれば、falseを返します。
  2. ||(OR):論理和演算子は、両側の式の少なくとも一方がtrueの場合にtrueを返します。両方がfalseの場合にfalseを返します。
  3. !(NOT):論理否定演算子は、式の真偽を反転させます。trueはfalseに、falseはtrueになります。

これらの演算子は、条件文やループなどの制御構造で論理式を組み立てるために使用されます。

ビット演算子[編集]

ビット演算子は、整数のビットレベルでの演算を実行します。Javaのビット演算子は、以下のようになります。

  1. &:ビット単位のAND演算を行います。
  2. |:ビット単位のOR演算を行います。
  3. ^:ビット単位のXOR(排他的論理和)演算を行います。
  4. ~:ビット単位の補数(ビット反転)演算を行います。
  5. <<:左シフト演算子は、ビットを左に指定された数だけシフトします。
  6. >>:符号付き右シフト演算子は、ビットを右に指定された数だけシフトします。符号ビットは左端のビット(MSB)にコピーされます。
  7. >>>:符号なし右シフト演算子は、ビットを右に指定された数だけシフトします。左端のビットは0になります。

これらの演算子は、ビット単位のデータ処理や、効率的なビットマスクの作成に使用されます。

代入演算子[編集]

代入演算子は、変数に値を割り当てるために使用されます。Javaの代入演算子には、単純な代入演算子と複合代入演算子があります。

  1. =:単純な代入演算子は、右辺の値を左辺の変数に代入します。
  2. +=:加算代入演算子は、左辺の変数に右辺の値を加算し、結果を左辺の変数に代入します。
  3. -=:減算代入演算子は、左辺の変数から右辺の値を減算し、結果を左辺の変数に代入します。
  4. *=:乗算代入演算子は、左辺の変数に右辺の値を乗算し、結果を左辺の変数に代入します。
  5. /=:除算代入演算子は、左辺の変数を右辺の値で除算し、結果を左辺の変数に代入します。
  6. %=:剰余代入演算子は、左辺の変数を右辺の値で剰余計算し、結果を左辺の変数に代入します。

これらの演算子は、変数の値を更新する際に使用され、簡潔なコードを記述するのに役立ちます。


式と演算子
public class Main {
    public static void main(String[] args) {
        int x = 5;
        int y = 3;
        
        // 算術演算子
        int sum = x + y; // 加算
        int difference = x - y; // 減算
        int product = x * y; // 乗算
        int quotient = x / y; // 除算
        int remainder = x % y; // 剰余
        
        // 比較演算子
        boolean isEqual = x == y; // xとyが等しいかどうか
        boolean isNotEqual = x != y; // xとyが等しくないかどうか
        boolean isGreaterThan = x > y; // xがyより大きいかどうか
        boolean isLessThan = x < y; // xがyより小さいかどうか
        boolean isGreaterOrEqual = x >= y; // xがy以上かどうか
        boolean isLessOrEqual = x <= y; // xがy以下かどうか
        
        // 論理演算子
        boolean andResult = (x > 0) && (y < 0); // 論理積(AND)
        boolean orResult = (x > 0) || (y < 0); // 論理和(OR)
        boolean notResult = !(x > 0); // 論理否定(NOT)
        
        // ビット演算子
        int bitAnd = x & y; // ビット単位のAND
        int bitOr = x | y; // ビット単位のOR
        int bitXor = x ^ y; // ビット単位のXOR
        int bitComplementX = ~x; // ビット単位の補数
        int leftShift = x << 1; // 左シフト
        int rightShift = x >> 1; // 右シフト
        
        // 代入演算子
        int a = 10;
        a += 5; // a = a + 5
        int b = 20;
        b -= 3; // b = b - 3
    }
}
このJavaプログラムでは、算術演算子、比較演算子、論理演算子、ビット演算子、代入演算子が使用されています。コメント中には各演算子の説明が含まれており、それぞれの演算子が何を行うかが明確に示されています。

用語集[編集]

  1. 式と演算子 (Expression and Operators):
    • 式 (Expression): プログラミングにおいて、値、演算子、変数、関数呼び出しなどから構成される計算を表す文法構造。プログラム内で評価され、結果の値を生成する。
    • 演算子 (Operator): 式内で値や変数を操作するための記号やキーワード。算術演算子、比較演算子、論理演算子、ビット演算子、代入演算子などがある。
  2. Javaにおける式と演算子 (Expression and Operators in Java):
    • 算術演算子 (Arithmetic Operators): 加算、減算、乗算、除算、剰余など、数値データ型の間で算術演算を実行するための演算子。
    • 比較演算子 (Comparison Operators): 等しい、等しくない、大なり、小なりなど、値や式の比較を行う演算子。
    • 論理演算子 (Logical Operators): 論理積 (AND)、論理和 (OR)、否定 (NOT) など、真偽値を操作するための演算子。
    • ビット演算子 (Bitwise Operators): 論理積、論理和、排他的論理和、否定など、ビット単位の操作に使用される演算子。
    • 代入演算子 (Assignment Operators): 代入、加算代入、減算代入、乗算代入など、変数に値を代入する演算子。
  3. 算術演算子 (Arithmetic Operators in Java):
    • 加算 (Addition): +。整数や浮動小数点数の加算。
    • 減算 (Subtraction): -。整数や浮動小数点数の減算。
    • 乗算 (Multiplication): *。整数や浮動小数点数の乗算。
    • 除算 (Division): /。浮動小数点数の除算。整数と浮動小数点数の場合もあり。
    • 剰余 (Modulus): %。整数や浮動小数点数の剰余。
  4. 多様な算術演算子の例 (Various Arithmetic Operators Example in Java):
    • Javaで異なるデータ型での算術演算子の使用例。
  5. InfinityとNaN (Infinity and NaN in Java):
    • Infinity (無限大): 有限の数値を0.0で割った場合やオーバーフローが発生した場合に発生。Double.POSITIVE_INFINITYで表現される。
    • -Infinity (負の無限大): 有限の負の数値を0.0で割った場合やオーバーフローが発生した場合に発生。Double.NEGATIVE_INFINITYで表現される。
    • NaN (非数): 0を0で割った場合や不正な演算が行われた場合に発生。Double.NaNで表現され、数値としての意味を持たないことを示す。

条件分岐[編集]

「条件分岐」は、プログラミングにおいて重要な概念の一つです。条件分岐を使うことで、プログラムは特定の条件に応じて異なる処理を実行することができます。

この章では、Javaでの条件分岐の基本的な使い方から、より高度な使い方までを解説します。if-else文、switch文、switch式、論理演算子、三項演算子など、様々な種類の条件分岐について学ぶことができます。また、例外処理における条件分岐の使い方についても解説します。

各セクションでは、実際のコード例を使って、どのように条件分岐を使えばよいかを説明します。また、練習問題も用意していますので、理解を深めるために挑戦してみてください。

条件分岐は、プログラムの制御構造を理解する上で重要な概念です。本章を通して、条件分岐の基本的な使い方から応用までを学び、プログラムの制御構造を理解してください。

if-else文[編集]

Javaのif-else文は、プログラムの流れを条件分岐させるための文です。条件に応じて実行される文を切り替えることができます。

if文は、指定された条件が真である場合に実行される文を指定します。if文が偽である場合に実行される文を指定するために、else節を組み合わせて使うことができます。

if-else文の基本構文は以下の通りです。

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

条件式は、真偽値を返す式です。もし条件式が真であれば、if文の中の文が実行され、偽であればelse節の中の文が実行されます。

また、else節は省略することができます。省略した場合、条件式が偽である場合には何も実行されません。

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

複数の条件を判定する場合には、else if節を使うことができます。

if (条件式1) {
    // 条件式1が true の場合に実行される文
} else if (条件式2) {
    // 条件式1が false かつ、条件式2が true の場合に実行される文
} else {
    // 条件式1も条件式2も false の場合に実行される文
}

複数の条件を判定する場合には、if-else文をネストして使うこともできます。

public class IfElseExample {
    public static void main(String[] args) {
        var n = 0.0 / 0.0;

        if (n < 0.0) {
            System.out.println("負の数です");
        } else if (n > 0.0) {
            System.out.println("正の数です。");
        } else if (n == 0.0) {
            System.out.println("零です。");
        } else {
            System.out.println(n + "です。");
        }
    }
}

このコードは、if-else文を使って変数nが負の数、正の数、零、またはNaN(非数)であるかを判定しています。

まず、変数nに0.0を0.0で割った結果を代入しています。0.0を0.0で割るとNaNになるため、この変数はNaNになります。

次に、if-else文を使って、nが負の数、正の数、零、またはNaNであるかを判定しています。

まず、n < 0.0という条件を使って、nが負の数であるかを判定しています。もしnが負の数であれば、System.out.println("負の数です");が実行されます。

次に、n > 0.0という条件を使って、nが正の数であるかを判定しています。もしnが正の数であれば、System.out.println("正の数です。");が実行されます。

次に、n == 0.0という条件を使って、nが零であるかを判定しています。もしnが零であれば、System.out.println("零です。");が実行されます。

最後に、else節を使って、nがNaNであるかを判定しています。NaNはどの数とも等しくならないため、n == 0.0n < 0.0n > 0.0のいずれの条件も成立しないため、else節が実行されます。else節では、nの値をそのまま表示するSystem.out.println(n + "です。");が実行されます。

このように、if-else文を使うことで、複数の条件を判定し、条件に応じた処理を行うことができます。

switch文[編集]

Javaのswitch文は、複数の条件分岐を処理するための構文です。特定の変数の値をチェックし、その値に応じて分岐することができます。

基本的な構文は以下の通りです。

switch () {
    case 値1:
        // 値1に対する処理
        break;
    case 値2:
        // 値2に対する処理
        break;
    default:
        // 上記のいずれの値にも一致しない場合の処理
        break;
}

式には、チェックする式を指定します。各caseには、変数が持つ値が一致する場合に実行される処理を記述します。defaultには、上記のいずれの値にも一致しない場合に実行される処理を記述します。

式には、数値以外に文字列も使うことが出来ます。

以下は、Javaのswitch文で文字列型を使用した例です。

public class SwitchStringExample {
    public static void main(String[] args) {
        String fruit = "りんご";
        
        switch (fruit) {
            case "りんご":
            case "バナナ":
            case "いちご":
            case "メロン":
                System.out.println(fruit + "は好きな果物です");
                break;
            default:
                System.out.println(fruit + "は果物ではありません");
                break;
        }
    }
}

この例では、変数fruitに文字列型の「りんご」が代入されています。switch文の条件式であるswitch (fruit)では、文字列型の変数fruitを使用しています。

switch文のcaseラベルには、文字列型の定数をカンマで区切って列挙しています。 また、caseラベルで果物として認識する文字列は、同じ文の中に複数記述することができます。 break文を使用して、該当するcaseラベルにマッチした場合は、それに続く文を実行するようにしています。

また、Javaのswitch文では、Enumを使った網羅性の確保ができます。Enumは、プログラムで扱う定数を列挙するためのクラスです。

以下は、Enumを使ったswitch文の例です。

import java.util.*;

public class SwitchEnumExample {
    public enum Animal {
        DOG,
        CAT,
        CANARY
    }

    public static void main(String[] args) throws Exception {
        Animal animal = Animal.CAT;

        switch (animal) {
            case DOG:
                System.out.println("ワンワン");
                break;
            case CAT:
                System.out.println("ニャー");
                break;
            case CANARY:
                System.out.println("ピューイ");
                break;
        }
    }
}

この例では、AnimalというEnumを定義し、それを使って動物の鳴き声を出力するプログラムを書いています。switch文のcaseには、Enumの要素を列挙しています。

switch文は、if文と比べて複数の条件分岐をスッキリと書くことができるため、コードの可読性が向上するという利点があります。

switch式[編集]

Java 12から、Javaにはswitch式という新しい構文が導入されました。switch式は、通常のswitch文と同様に、複数の値の比較に基づいて異なるコードブロックを実行するために使用されますが、式の値を返すこともできます。

switch式は、通常のswitch文と同じように、いくつかのcaseブロックを持ちます。ただし、switch式では、個々のcaseラベルに式を直接使用できます。また、値を返すことができるため、式の値を変数に代入することもできます。

Javaのswitch式の構文は以下の通りです。

result = switch () {
    case 値1 -> 式1;
    case 値2 -> 式2;
    case 値3, 値4 -> {
        // multiple lines of expressions
        式3;
        yeild 式4;
    }
    default -> 式5;
};
  • switchキーワードに続いて、条件判定に用いる式を指定します。この式の結果に基づいて、次のcase文に分岐します。
  • caseキーワードに続いて、条件値を指定します。この条件値が、式の結果と等しい場合、その次の行に記述された式を実行します。
  • ->の後に続く式は、そのcaseで実行する処理を定義します。
  • 複数の条件値を一つのcase文で指定することもできます。この場合、条件値はコンマで区切って指定します。
  • 複数の式を実行したい場合は、中括弧 {} 内に複数の式を記述します。
    • この場合、ブロックの値は yeild 式の形で指定します。
  • defaultキーワードに続いて、どのcaseにも該当しない場合に実行する式を指定します。
  • 最後に、switch式の結果を代入する変数を指定します。代入は、=記号の左辺に変数名を、右辺にswitch式を指定します。

なお、switch式はJava 12から導入された新しい機能であり、以前のバージョンのJavaでは使用できません。

以下は、switch式の例です。

public class SwitchExpressionExample {
    public static void main(String[] args) {
        String fruit = "りんご";
        var result = switch (fruit) {
            case "りんご", "バナナ", "いちご" -> 1;
            case "メロン", "スイカ" -> 2;
            default -> 0;
        };
        System.out.println(fruit + "の評価結果は " + result);
    }
}

この例では、変数fruitに文字列型の「りんご」が代入されています。switch式では、変数fruitを評価しています。caseラベルには、直接式を使用しています。caseラベルで果物として認識する文字列は、同じ文の中にカンマで区切って複数記述することができます。->演算子を使用して、各caseラベルの式を実行します。

switch式の最後には、値を返すことができます。この例では、式の結果を変数resultに代入しています。最後に、変数resultの値を出力しています。

switch式はフォールスルーしません
switch文において、あえてbreak文を省略して、次のcaseの処理を実行することを「フォールスルー(fall-through)」と呼びます。

switch文でフォールスルーを行う場合は、明示的にコメントでその旨を記述することが推奨されます。

一方、switch式においては、フォールスルーの概念は存在せず、不用意な処理の続行を避けることができます。


論理演算子[編集]

Javaにおいて、条件式は比較演算子や論理演算子を用いて、複数の条件を組み合わせた式を表現することができます。論理演算子は、2つのブーリアン値(trueまたはfalse)を受け取り、新しいブーリアン値を返します。

Javaには、5つの論理演算子があります。

  • 論理積(&&): 2つの式が両方ともtrueの場合にtrueを返します。例えば、式A && 式Bは、式Aがfalseの場合には評価を中止して、式Bを評価しません。
  • 論理和(||): 2つの式のどちらかがtrueの場合にtrueを返します。例えば、式A || 式Bは、式Aがtrueの場合には評価を中止して、式Bを評価しません。
  • 論理否定(!): 式がtrueの場合はfalseを、falseの場合はtrueを返します。例えば、!式Aは、式Aがfalseの場合にはtrueを返し、式Aがtrueの場合にはfalseを返します。
  • 排他的論理和(!=): 2つの式が不一致の場合にtrueを返します。短絡評価は行われません。
  • 排他的論理和(==): 2つの式が一致した場合にtrueを返します。短絡評価は行われません。

以下は、論理演算子(AND、OR、NOT)の真理値表を表形式で示したものです。

論理演算子の真理値表
A B !A A && B A || B
false false true false false
false true true false true
true false false false true
true true false true true

この表では、AとBがそれぞれ真(true)または偽(false)の場合に対する、NOT、AND、ORの結果が示されています。

三項演算子[編集]

Javaの三項演算子は、条件式 ? 式1 : 式2 の形式を持ちます。この演算子は、条件式が true の場合は式1を、falseの場合は式2を評価して返します。例えば、以下のようなコードが考えられます。

var a = 5;
var b = 10;
var max = a > b ? a : b;
System.out.println("最大値は" + max);

このコードでは、aとbの値を比較して、aがbよりも大きければaを、そうでなければbを最大値として選択します。 三項演算子を使って、if文を使う代わりに簡潔に書くことができます。 ただし、三項演算子は条件式と2つの式のみを評価するので、複雑な条件分岐を行う場合にはif文を使用することが推奨されます。

パターンマッチング式[編集]

Java 16で導入されたパターンマッチング式(Pattern Matching for instanceof)は、Java言語の制御構造の一つです。

通常、オブジェクトの型を判定するためには instanceof 演算子を使用します。パターンマッチング式は、この instanceof 演算子をより簡潔かつ安全に使用できるようにしたものです。

例えば、次のようなコードがあります。

if (obj instanceof String) {
    String str = (String) obj;
    System.out.println(str.toUpperCase());
}

このコードは、オブジェクトが String クラスのインスタンスである場合に、そのオブジェクトを String 型にキャストして大文字に変換し、標準出力に出力するという処理を行っています。

パターンマッチング式を使用すると、このコードを次のように書き換えることができます。

if (obj instanceof String str) {
    System.out.println(str.toUpperCase());
}

このコードでは、オブジェクトが String クラスのインスタンスである場合に、そのオブジェクトを String 型にキャストせずに、変数 str に直接代入しています。また、変数 str は if 文の中でのみ有効なローカル変数となります。

このように、パターンマッチング式を使用することで、より簡潔で安全なコードを書くことができます。

switchのパターンマッチング拡張[編集]

switchのパターンマッチング拡張とは、Javaプログラミング言語において、switch文やswitch式においてパターンを使用して条件を指定できるようにする機能です。通常のswitch文やswitch式では、一致する値の厳密な等式比較しか行えませんでしたが、パターンマッチング拡張により、より柔軟な条件指定が可能になります。

具体的には、switch文やswitch式のケースラベルで、従来の定数だけでなく、パターンも指定できるようになります。これにより、オブジェクトの型や構造に基づいて条件を指定することができます。例えば、オブジェクトが特定の型であるか、あるいは特定のフィールドの値を持つかどうかなどの条件を指定することができます。

これにより、従来は複雑だった複数の条件分岐を一つのswitch文やswitch式で表現することができるようになり、コードの可読性が向上します。また、パターンマッチングにより、より安全な条件指定が可能になります。

以下は、Java 21で導入されたswitch文のパターンマッチング拡張を使用したコード例です。

public class PatternMatchingExample {
    public static void main(String[] args) {
        Object obj = "Hello";

        String result = formatterPatternSwitch(obj);
        System.out.println(result);
    }

    static String formatterPatternSwitch(Object obj) {
        return switch (obj) {
            case Integer i -> String.format("int %d", i);
            case Long l -> String.format("long %d", l);
            case Double d -> String.format("double %f", d);
            case String s -> String.format("String %s", s);
            default -> "unknown";
        };
    }
}

この例では、formatterPatternSwitchメソッド内で、switch文を使用してobjの型に基づいて処理を分岐しています。各ケースラベルでは、オブジェクトが特定の型にマッチするかどうかをパターンで指定しています。例えば、case Integer iでは、objInteger型にマッチする場合、iというパターン変数が導入され、その値がint %dのフォーマット文字列に埋め込まれます。他の型についても同様の処理が行われます。

このように、switch文のパターンマッチング拡張を使用することで、よりシンプルで効率的なコードを記述することができます。


以下は、Java 21で導入されたswitch文のパターンマッチング拡張で使用できるパターンの一覧を表形式で示したものです。

switchのパターンマッチング拡張で使用できるパターンの一覧
パターン 説明
型パターン 特定の型に一致するかどうかをチェックする。
nullパターン nullに一致するかどうかをチェックする。
リテラルパターン 指定されたリテラル値に一致するかどうかをチェックする。
列挙型定数パターン 指定された列挙型定数に一致するかどうかをチェックする。
配列パターン 指定された配列の要素の数と値に一致するかどうかをチェックする。
デコンストラクタパターン オブジェクトの構造を分解して、特定のフィールドや要素の値に一致するかどうかをチェックする。
インスタンスパターン 指定されたインスタンスのプロパティに一致するかどうかをチェックする。

これらのパターンを使用して、switch文やswitch式のケースラベルで条件分岐を行うことができます。それぞれのパターンは、特定の条件にマッチするかどうかをチェックするために使用されます。

反復[編集]

反復 (Iteration) は、同じ処理を繰り返し実行することで、コードの簡潔さと再利用性を向上させるためによく使用されます。Javaには、様々な方法で反復処理を行うことができます。たとえば、for文while文do-while文拡張for文IteratorforEachメソッドなどがあります。

このチュートリアルでは、これらの反復処理方法を解説し、それぞれの使用方法や適切な場面について説明します。また、配列やコレクションに対する反復処理、ループ制御についても解説します。

反復処理は、プログラミングにおいて非常に重要な概念であり、プログラムの処理効率や保守性を向上させるためにも、しっかりと理解しておく必要があります。本チュートリアルを通じて、反復処理について深く理解し、効果的に使用するための知識を身につけましょう。

反復処理の例[編集]

Wikipedia
Wikipedia
ウィキペディアループ文の記事があります。

次のサンプルは、一応Hello worldの日本語版です。 Hello world同様、実用的な意味はありませんが、反復処理の例となっています。

Main.java
class Main {
    public static void main(String[] args) {
        String hello = "世界🌍よこんにちは😀";
        for (int i = 0, len = hello.length(); i < len; i = hello.offsetByCodePoints(i, 1)) {
            System.out.println(Character.toChars(hello.codePointAt(i)));
        }
    }
}

上の例はfor文と呼ばれる構文を使った例です(4行目にキーワード「for」があることに注意してください)。 コンパイルして実行してみましょう。

$ javac Main.java
$ java Main
世
界
🌍
よ
こ
ん
に
ち
は 
😀
“縦書き”でメッセージが表示されます。

このプログラムはwhile文を使って次のように書くこともできます。

class Main {
    public static void main(String[] args) {
        String hello = "世界🌍よこんにちは😀";
        int i = 0, len = hello.length(); 
        while (i < len) {
            System.out.println(Character.toChars(hello.codePointAt(i)));
            i = hello.offsetByCodePoints(i, 1);
        }
    }
}

さらにdo-while文を使って次のような書き方もできます。

class Main {
    public static void main(String[] args) {
        String hello = "世界🌍よこんにちは😀";
        int i = 0, len = hello.length(); 
        do {
            System.out.println(Character.toChars(hello.codePointAt(i)));
            i = hello.offsetByCodePoints(i, 1);
        } while (i < len);
    }
}

またさらに、CharSequence#codePoints()でコードポイントのStreamを取得し、これのforEachメソッドで繰返しを行う次のような書き方も可能です。 これが最もシンプルな書き方です。

class Main {
    public static void main(String[] args) {
        new String("世界🌍よこんにちは😀").codePoints().forEach(cp -> System.out.println(Character.toChars(cp)));
    }
}
もはや構文ですらありませんが、サロゲートペアを含むコードポイントの列を繰返していることを簡素に表現できています。

反復条件によく使われる比較演算子[編集]

各構文の詳細を説明する前に、共通する要素について説明します。

反復には、必ず反復条件を伴います。反復は、反復条件が満たされている間だけ続けられ、条件が満たされなくなると終了する。

反復条件は、比較演算子を使って表現されることがあります。 比較演算子は不等号などの数学記号に似ています。

比較演算子一覧
比較演算子 数学記号 意味
== 左辺と右辺が等しい場合にtrueを返します。
!= 左辺と右辺が等しくない場合にtrueを返します。
< 左辺が右辺よりも小さい場合にtrueを返します。
> 左辺が右辺よりも大きい場合にtrueを返します。
<= 左辺が右辺以下の場合にtrueを返します。
>= 左辺が右辺以上の場合にtrueを返します。
instanceof N/A 左辺のオブジェクトが右辺のクラスのインスタンスである場合にtrueを返します。

==演算子は、プリミティブ型の値またはオブジェクトの参照を比較するために使用されます。!=演算子は、==演算子と同じように使用されますが、2つの値が等しくない場合にtrueを返します。

<><=>=演算子は、プリミティブ型の値の大小関係を比較するために使用されます。

instanceof演算子は、オブジェクトの型を調べるために使用されます。左辺が右辺のクラスのインスタンスである場合、trueを返します。

注意点としては、オブジェクトの比較に==演算子を使用すると、オブジェクトの参照を比較するため、同じ内容のオブジェクトでもfalseを返す場合があります。 オブジェクトの内容を比較する場合は、.equals()メソッドを使用する必要があります。

for文[編集]

Wikipedia
Wikipedia
ウィキペディアfor文の記事があります。

Javaのfor文は、反復処理を行うための制御構造の一つで、指定された回数または条件を満たすまで繰り返します。一般的に、以下の形式で使用されます。

for (初期化式; 継続条件式; 更新式) {
    // 反復処理の本体
}
初期化式
初期化式は、反復処理が始まる前に一度だけ評価される式で、反復処理の前に何らかの変数を初期化するために使用されます。
初期化式では変数を宣言することができ、初期化式で宣言された変数のスコープはfor文が終わるまでです。
継続条件式
継続条件式は、反復処理が継続するかどうかを判定するための式で、trueかfalseを返します。この式がtrueを返し続ける限り、反復処理が繰り返されます。
継続条件式がfalseを返した場合、反復処理は終了します。
更新式
更新式は、反復処理の本体が実行された後に評価される式で、反復変数などの値を更新するために使用されます。

for文の本体は、継続条件式がtrueを返す間、繰り返し実行されます。通常、変数の値を使って何らかの処理を行います。

以下は、1から10までの整数を出力する例です。

for (int i = 1; i <= 10; i++) {
    System.out.println(i);
}
このコードは、1から10までの整数を順番に出力するための反復処理を行います。
for文の初期化式 int i = 1 では、反復処理で使用する変数 i を1で初期化しています。
継続条件式 i <= 10 では、変数 i の値が10以下の間、反復処理を繰り返すことを指定しています。
更新式 i++ では、変数 i を1ずつ増加させます。
反復処理の本体 System.out.println(i) では、変数 i の値を画面に出力しています。
つまり、初期値が1であり、10以下の間、変数 i を1ずつ増加させながら、各ループで変数 i の値を画面に出力することを指定しているため、1から10までの整数が順番に出力されます。

掛け算九九の例[編集]

for文の学習と言えば、典型的な例が掛け算九九を表示するサンプルです。

class Main {
    public static void main(String[] args) {
        for (int y = 1; y <= 9; y++) {
            for (int x = 1; x <= 9; x++) {
                 String buf = String.format("%dx%d=%2d ", x, y, x * y);
                 System.out.print(buf);
            }
            System.out.println();
        }
    }
}
外側のforループは、行ごとに反復処理を行います。 内側のforループは、各行に対して、列ごとに反復処理を行います。
内側のforループの中で、String.formatメソッドを使って、現在の行と列の値に対応する九九の計算結果を文字列として作成し、それをSystem.out.printメソッドで出力しています。
外側のforループの最後には、改行を出力するためにSystem.out.printlnメソッドを呼び出しています。これにより、各行が改行で区切られて表示されるようになります。

拡張for文[編集]

Wikipedia
Wikipedia
ウィキペディアforeach文の記事があります。


Javaにおいて、拡張for文(またはfor-each文)は、配列やコレクションなどの要素を繰り返し処理するための簡潔な方法を提供します。 標準的なforループとは異なり、ループカウンタを使用する必要がなく、ループ対象のデータ型に応じてループ変数を明示的に宣言する必要がありません。

構文は以下のようになります。

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

以下に、配列やコレクションを用いた拡張for文の例を示します。

// 配列の例
int[] nums = {1, 2, 3, 4, 5};
for (int num : nums) {
    System.out.println(num);
}

// コレクションの例
List<String> fruits = new ArrayList<>();
fruits.add("apple");
fruits.add("banana");
fruits.add("orange");
for (String fruit : fruits) {
    System.out.println(fruit);
}

この例では、配列numsの要素を順に表示するためにint型のループ変数numを使用し、同様に、コレクションfruitsの要素を順に表示するためにString型のループ変数fruitを使用しています。 拡張for文を使用することで、コードがより簡潔で読みやすくなります。

拡張for文
なお、この例では配列を使って説明していますが、拡張for文が使えるのは配列だけではありません。(少し先取りした内容になりますが)コレクションフレームワークや、もっと一般的に言うとIterable<E>を実装したクラスが拡張for文で使えます。具体的には、
for (E var1 : /* Iterable<E>を実装したクラスのインスタンス */) {
  // ここに処理を書く
}

という構文になります。 拡張for文は、そうしたインスタンスにも配列同様の考え方で適用することができます。


while文[編集]

Wikipedia
Wikipedia
ウィキペディアwhile文の記事があります。

Javaにおけるwhile文は、指定した条件式がtrueである間、反復処理を続ける制御構造です。構文は以下の通りです。

while (条件式) {
    // 反復処理の本体
}

条件式がtrueである限り、中括弧内の文が繰り返し実行されます。条件式がfalseになった時点で、while文の実行は終了します。

例えば、1から10までの整数を出力するプログラムは以下のように書けます。

int i = 1;
while (i <= 10) {
    System.out.println(i);
    i++;
}

このプログラムでは、変数iを1で初期化し、iが10以下である限り、iを出力してiを1ずつ増やしています。

これをStreamを使用して書き換えることができます。

IntStream.rangeClosed(1, 10)
         .forEach(System.out::println);

IntStream.rangeClosed(1, 10)は、1から10までの整数のストリームを生成します。そして、.forEach(System.out::println)で各要素を出力しています。

rangeClosed()メソッドは指定された範囲(この場合は1から10まで)の整数ストリームを生成します。このストリームを使用して各要素に対して操作を行うことができます。

ファイルの読み込みの例[編集]

Javaにおいて、whileループを使ってファイルを読み込む方法について説明します。

以下は、例としてファイルの中身を1行ずつ読み込み、コンソールに出力するプログラムです。

import java.io.*;

public class FileReadDemo {
    public static void main(String[] args) {
        try {
            // ファイルの読み込みに必要な準備
            BufferedReader br = new BufferedReader(new FileReader("input.txt"));
            String line;

            // ファイルの1行ずつ読み込み
            while ((line = br.readLine()) != null) {
                // 読み込んだ行をコンソールに出力
                System.out.println(line);
            }

            // ファイルを閉じる
            br.close();
        } catch (IOException e) {
            System.out.println("ファイル読み込みエラー");
        }
    }
}

まず、BufferedReader クラスを使ってファイルを読み込むための準備をします。BufferedReader クラスは、テキストファイルを1行ずつ読み込むためのクラスで、FileReader クラスと組み合わせて使用します。

while ループ内では、BufferedReader オブジェクトの readLine() メソッドを使って、ファイルから1行ずつデータを読み込みます。読み込んだ行が null でない場合は、読み込んだ行をコンソールに出力します。

ファイルの読み込みが終了したら、ファイルを閉じるために close() メソッドを呼び出します。また、エラーが発生した場合は、例外処理を行います。

このように、while ループを使ってファイルを読み込むことができます。ただし、ファイルの読み込みには例外処理が必要であることに注意してください。

参考:(line = in.readLine()) != nullのような書き方について

上記のサンプルでは、while文の反復条件が(line = in.readLine()) != nullと書かれています。 これは代入演算と比較演算を同時に行う書き方で、こうした類の処理によく使われるパターンですが、慣れない間は奇異に見えるかもしれません。

なぜこうした書き方が可能なのかというと、代入演算の式は、その式で代入結果の値を返すからです。 念のため、処理の流れを追ってみましょう。

まず括弧内の処理、つまりline = in.readLine()が実行されます。この式は、変数lineに代入された値を返します。要するに、全体でlineが返されると考えてよいでしょう。

続いて、比較演算が行われます。括弧内をlineに置き換えるとわかりよいでしょう。つまりline != nullという判定が行われることになります。linenullになった場合、行はそれ以上ないというサインなので、ループから抜ける必要があります。

参考:for文で書いた場合

上記のサンプルは、for文を使ってたとえば

import java.io.*;

public class FileReadDemo {
    public static void main(String[] args) {
        try {
            // ファイルの読み込みに必要な準備
            BufferedReader br = new BufferedReader(new FileReader("input.txt"));
            String line;

            // ファイルの1行ずつ読み込み
            for (line = br.readLine(); line != null; line = br.readLine()) {
                // 読み込んだ行をコンソールに出力
                System.out.println(line);
            }

            // ファイルを閉じる
            br.close();
        } catch (IOException e) {
            System.out.println("ファイル読み込みエラー");
        }
    }
}

と書くこともできます。 コードの効率性や可読性、保守性なども考慮して判断する必要があります。

 

参考:Streamを使った場合

さらに、ファイル読み込みのコードをStreamを使用して書き換えることができます。BufferedReaderからの行のストリームを取得し、それを使用して各行を処理する方法があります。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class FileReadDemo {
    public static void main(String[] args) {
        try {
            // ファイルの1行ずつストリームとして読み込む
            Files.lines(Paths.get("input.txt"))
                    .forEach(System.out::println);
        } catch (IOException e) {
            System.out.println("ファイル読み込みエラー");
        }
    }
}

このコードでは、Files.lines(Paths.get("input.txt"))を使用して、ファイルを行のストリームとして読み込んでいます。そして、.forEach(System.out::println)を使って、各行をコンソールに出力しています。

Files.lines()はファイルを行のストリームとして読み込む便利な方法です。それを使用することで、BufferedReaderを明示的に使わずにファイルをストリームとして扱うことができます。

do-while文[編集]

Wikipedia
Wikipedia
ウィキペディアdo-while文の記事があります。

Javaのdo-while文は、while文と同じくループ処理を行うための構文の1つです。ただし、while文と異なり、do-while文はループの最初に1度だけブロック内の処理を実行し、その後に条件式を評価します。条件式がtrueの場合、再びブロック内の処理を実行します。条件式がfalseの場合、ループから抜けます。

do-while文の基本構文は以下のようになります。

do {
  // 処理
} while (条件式);

例えば、1から10までの整数を順番に出力する場合は、次のようにdo-while文を使用することができます。

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

このコードでは、変数iを初期化してから、doブロック内でiを出力し、iを1増やしています。その後、while文でiが10以下である限り、doブロックを繰り返し実行します。結果として、1から10までの整数が順番に出力されます。

do-while文は、ループの最初に必ず1度だけブロック内の処理を実行する必要がある場合に使用することができます。また、条件式がfalseであっても、ブロック内の処理を最低1回実行することが保証されるため、while文と異なり、特定の処理を必ず実行する必要がある場合にも適しています。

Iterator[編集]

JavaのIteratorは、コレクションオブジェクト内の要素を順番に取得するためのインターフェースです。Iteratorは、Javaのコレクションフレームワークの一部であり、java.utilパッケージに含まれています。

Iteratorを使用することで、配列やリストなどのコレクションオブジェクトの要素を順番に取得し、処理を行うことができます。Iteratorは、以下の3つのメソッドを持っています。

  • boolean hasNext(): 次の要素がある場合にtrueを返します。
  • E next(): 次の要素を返します。
  • void remove(): 最後に返された要素をコレクションから削除します。

Iteratorの基本的な使い方は、以下のようになります。

Iterator<E> it = collection.iterator();   // イテレータを取得
while (it.hasNext()) {                    // 次の要素がある場合
    E element = it.next();                // 次の要素を取得
    // 要素に対する処理
}

ここで、collectionは要素を持つコレクションオブジェクトです。まず、iterator()メソッドを使用してイテレータを取得し、hasNext()メソッドで次の要素があるかどうかを確認します。次の要素がある場合、next()メソッドで次の要素を取得し、処理を行います。

また、Iteratorは、要素を削除するためのremove()メソッドを持っています。このメソッドを使用する場合は、必ずnext()メソッドで要素を取得した直後に呼び出す必要があります。例えば、次のように使用することができます。

Iterator<E> it = collection.iterator();
while (it.hasNext()) {
    E element = it.next();
    if (条件) {
        it.remove();  // 条件に合致する要素を削除
    }
}

Iteratorを使用することで、コレクションオブジェクトの要素を順番に取得し、必要な処理を行うことができます。ただし、Iteratorは単方向のイテレーションしかサポートしていないため、要素の逆順の処理が必要な場合は、リストイテレータを使用することが推奨されます。

forEachメソッド[編集]

JavaのforEachメソッドは、Java 8から導入された機能で、配列やコレクションの要素を繰り返し処理するためのメソッドです。forEachメソッドは、以下のように使用します。

arrayOrCollection.forEach(element -> {
    // 要素に対する処理
});

ここで、arrayOrCollectionは、要素を持つ配列またはコレクションオブジェクトです。forEachメソッドは、要素ごとに指定された処理を行うためのラムダ式を引数として受け取ります。

ラムダ式は、->を用いて定義されます。上記の例では、elementという変数が要素を表し、{}内には要素に対する処理が記述されます。この場合、forEachメソッドは、配列またはコレクションの要素を繰り返し、各要素に対して指定された処理を行います。

forEachメソッドは、拡張for文に比べて、コードを簡潔に書くことができます。また、複数の要素に対して同じ処理を行う場合にも適しています。

forEachメソッドは、配列やコレクションの要素を順番に処理するため、要素の追加や削除などの操作を行う場合は、for文またはIteratorを使用する必要があります。また、forEachメソッドは、並列処理にも対応しており、parallelStreamメソッドと組み合わせて使用することで、複数のスレッドを使用した並列処理が可能です。

Javaのコレクションフレームワークを使用してリスト(List)、セット(Set)、およびマップ(Map)を作成し、それらの要素を表示する例

import java.util.*;

public class CollectionExample {
    public static void main(String[] args) {
        // Listの例
        List<String> stringList = List.of("apple", "banana", "orange");

        // forEachメソッドを使って要素を表示
        stringList.forEach(System.out::println);

        // Setの例
        Set<Integer> integerSet = Set.of(1, 2, 3, 4, 5);

        // forEachメソッドを使って要素を表示
        integerSet.forEach(System.out::println);

        // Mapの例
        Map<Integer, String> numberMap = Map.of(
            1, "One",
            2, "Two",
            3, "Three"
        );

        // forEachメソッドを使ってキーと値を表示
        numberMap.forEach((key, value) -> System.out.println(key + " : " + value));
    }
}

コードの概要:

  1. List<String>を使用して、3つの文字列を持つリスト stringList を作成しています。それから、forEach メソッドを使用して、リストの各要素を改行して表示しています。
  2. Set<Integer>を使用して、5つの整数を持つセット integerSet を作成しています。同様に、forEach メソッドを使用して、セットの各要素を改行して表示しています。
  3. Map<Integer, String>を使用して、3つの整数をキーとし、それに対応する文字列を値とするマップ numberMap を作成しています。forEach メソッドを使用して、マップの各エントリー(キーと値のペア)をキーと値の形式で表示しています。

各コレクション(リスト、セット、マップ)は、Java 9で導入された List.of()Set.of()Map.of() メソッドを使用して作成されています。これらのメソッドは、不変のコレクションを作成し、指定された要素で初期化する便利な方法を提供します。そして、forEach メソッドは、各要素に対して指定されたアクション(この場合は表示)を実行するために使用されています。

List.ofメソッドは、指定された要素から不変のリストを作成するために使用されます。つまり、この場合、"apple", "banana", "orange" の3つの要素を持つリストが作成されます。

そして、forEachメソッドは、リスト内の各要素に対して指定されたアクションを実行します。System.out::printlnは、メソッド参照を使っています。これはprintlnメソッドへの参照を表しています。

つまり、fruits.forEach(System.out::println);は、リストの各要素をSystem.out.printlnメソッドを使って出力するという意味です。

ofメソッド
Javaのofメソッドは、Java 9から導入された静的メソッドであり、不変(immutable)なコレクション(List、Set、Map)を作成するための便利な方法を提供します。このメソッドは、複数の要素をコンパクトな方法で指定し、それらの要素を含む不変のコレクションを生成します。

ofメソッドを使用する主な理由は次の通りです:

  1. 不変性の確保: ofメソッドで作成されたコレクションは不変(immutable)です。つまり、一度作成された後はその内容を変更することができません。この性質は、プログラムの安全性とスレッドセーフ性を高めるのに役立ちます。
  2. コードの可読性と簡潔さ: ofメソッドは、コレクションを作成するためのリテラル構文よりも簡潔で読みやすいコードを提供します。複数の要素を指定するための煩雑なコードを省略できます。
  3. エラープルーフ: ofメソッドは可変長引数を取るため、要素を列挙する際にコンパイル時のチェックを提供します。これにより、コンパイル時にエラーを検出することができます。また、要素の型が一致しない場合や、nullを渡した場合には実行時に例外がスローされます。

ただし、ofメソッドにはいくつかの制限もあります。例えば、作成されるコレクションの要素数に制限があること、不変性を保つために要素の追加や削除ができないこと、またnull要素を受け付けないことなどが挙げられます。

したがって、短い要素のリストや、要素が事前にわかっている場合にはofメソッドを使用することでコードの可読性と堅牢性を高めることができます。ただし、要素が動的に変化する可能性がある場合や、大量の要素を扱う場合には、他の手法やコレクションの生成方法を検討する必要があります。


メソッドチェイン[編集]

メソッドチェインは、Javaで複数のメソッド呼び出しを1つの文でつなげて書く方法です。これにより、コードがより簡潔で読みやすくなります。例を見てみましょう。

import java.util.List;
import java.util.stream.Collectors;

public class MethodChainingExample {
    public static void main(String[] args) {
        List<String> words = List.of("apple", "banana", "orange", "grape", "peach");

        // 文字数が5未満の単語を取り出し、大文字に変換してカンマ区切りの文字列にする
        String result = words.stream()
            .filter(word -> word.length() < 5) // 文字数が5未満の単語をフィルタリング
            .map(String::toUpperCase) // 単語を大文字に変換
            .collect(Collectors.joining(", ")); // カンマ区切りの文字列に変換

        System.out.println(result);
    }
}

この例では、List.ofメソッドを使用してリストを作成し、それをストリームに変換しています。そして、メソッドチェインを使用していくつかの処理を行っています。

  1. filter: 文字数が5未満の単語をフィルタリングします。
  2. map: フィルタリングされた単語を大文字に変換します。
  3. collect: 変換された単語をカンマ区切りの文字列に集約します。

これにより、1つのストリーム処理内で複数の操作を行い、最終的な結果を得ることができます。メソッドチェインを使うと、コードがシンプルで、各ステップが連続しているため、処理の流れがより明確になります。

メソッドチェインの長所短所
メソッドチェインにはいくつかの長所と短所があります。

長所:

  1. コードの可読性向上: メソッドチェインを使用することで、複数のメソッド呼び出しを1行で表現できます。これにより、コードが簡潔になり、処理の流れが直感的に理解しやすくなります。
  2. 柔軟性と拡張性: メソッドチェインは、メソッドを順番に適用するため、フィルタリングやマッピングなどの処理を柔軟に組み合わせることができます。また、新しい処理が追加される場合も、既存のメソッドチェインに容易に組み込むことができます。
  3. 効率性の向上: 一連の操作をメソッドチェインでつなげることで、中間データ構造を作成することなく処理をパイプライン化できます。これにより、メモリの使用を最適化し、効率的な処理を実現できます。

短所:

  1. デバッグが難しいこと: メソッドチェインが長くなると、デバッグやエラーの特定が難しくなる場合があります。特に途中で行われる変換やフィルタリングなど、一連の操作が複雑になると、それぞれのステップでのデータの状態を理解するのが困難になることがあります。
  2. 可読性の低下: あまりにもメソッドチェインが長すぎる場合、コードの可読性が低下する可能性があります。メソッドチェインが複雑になると、理解しやすさが損なわれることがあります。
  3. エラーハンドリングの複雑化: メソッドチェイン内でエラーが発生した場合、どのメソッド呼び出しで問題が発生したのか特定することが難しくなることがあります。エラーのハンドリングやトラブルシューティングが複雑になる可能性があります。

メソッドチェインは、適切に使用されるとコードをスッキリとさせ、処理の流れを明確にすることができます。しかし、過度に長くなると可読性が低下したり、デバッグが難しくなるリスクもあるため、バランスを考えながら適切に利用することが重要です。


附録[編集]

チートシート[編集]

以下は、Javaで反復処理を行う際に使用する主要な文法とメソッドのチートシートです。

for文
for (初期化式; 条件式; 更新式) {
  // 処理
}
  • 初期化式: ループの最初に一度だけ実行され、変数の初期化を行う。
  • 条件式: 毎回ループの開始時に評価され、真偽値を返す。
  • 更新式: ループの最後に毎回実行され、変数の更新を行う。
while文
while (条件式) {
  // 処理
}
  • 条件式: 毎回ループの開始時に評価され、真偽値を返す。
do-while文
do {
  // 処理
} while (条件式);
  • 条件式: ループの最後に一度だけ評価され、真偽値を返す。
Enhanced for文
for ( 変数名 : 配列またはコレクション) {
  // 処理
}
  • 型: 配列またはコレクションに含まれる要素の型。
  • 変数名: ループ内で要素にアクセスするための変数名。
Iterator
Iterator<> iterator = コレクション.iterator();
while (iterator.hasNext()) {
   要素 = iterator.next();
  // 処理
}
  • 型: コレクションに含まれる要素の型。varを使うと型推論が可能。
  • iterator(): コレクションからイテレータを取得するメソッド。
  • hasNext(): 次の要素があるかどうかを判定するメソッド。
  • next(): 次の要素を取得するメソッド。
forEachメソッド
配列またはコレクション.forEach(要素 -> {
  // 処理
});
  • forEach(): 配列またはコレクションの要素を1つずつ取り出して、ラムダ式による処理を実行するメソッド。
  • 要素 -> {}: ラムダ式の記法。要素に対する処理を記述する。

用語集[編集]

  • ループ (Loop):同じ処理を繰り返し実行するプログラム構造。Javaではfor文、while文、do-while文などがあり、配列やコレクションに対しても反復処理を行うことができる。
  • 初期化式 (Initialization):for文で使用される、ループの最初に一度だけ実行される式。変数の宣言と初期化を行うことができる。
  • 条件式 (Condition):ループの開始時に評価される式。真偽値を返す。
  • 更新式 (Update):for文やwhile文で使用される、ループの最後に毎回実行される式。変数の更新などを行うことができる。
  • 配列 (Array):同じ型の複数の値を格納できる、固定長のデータ構造。インデックスを指定することで個々の要素にアクセスすることができる。
  • コレクション (Collection):複数のオブジェクトを格納するための可変長のデータ構造。Javaでは、List、Set、Mapなどがある。
  • Enhanced for文 (Enhanced for loop):配列やコレクションに対して反復処理を行うための構文。for (型 変数名 : 配列またはコレクション) { // 処理 }の形式で記述する。
  • Iterator:コレクションに対して反復処理を行うためのインターフェース。hasNext()、next()などのメソッドを提供する。
  • forEachメソッド (forEach):配列やコレクションに対してラムダ式を用いて反復処理を行うためのメソッド。配列またはコレクション.forEach(要素 -> { // 処理 });の形式で記述する。

[編集]

プログラミングにおける「型」(または「データ型」)は、データの種類や性質を表す概念です。プログラミング言語において、変数、関数の引数や戻り値、オブジェクトなどの要素には、それぞれ特定の型が割り当てられます。型は、そのデータがどのような値や操作を持ち、どのようにメモリ上で表現されるかを決定します。

プログラミングにおける型の役割は次のようなものがあります:

  1. データの性質を表現する: 型は、データがどのような性質を持つかを表現します。例えば、整数型は整数の値を表し、文字列型は文字列のシーケンスを表します。
  2. メモリの割り当てと管理: 型は、データがメモリ上でどのように表現されるかを定義します。これにより、適切なメモリの割り当てと管理が行われます。
  3. 演算と操作の定義: 型は、そのデータ型に対して許可される演算や操作を定義します。例えば、整数型では加算や減算などの算術演算が可能ですが、文字列型では文字列の結合や比較などが可能です。
  4. プログラムの正確性と安全性の確保: 型システムは、プログラム内でのデータの正確性と安全性を保証します。型によって、不適切な型の操作や予期しないデータの変換が防止されます。

プログラミングにおける型は、プログラムの構造や振る舞いを理解し、データを適切に扱うための基本的な概念です。適切な型の選択と使用は、プログラムの正確性、効率性、保守性を向上させるのに役立ちます。

Javaにおける型[編集]

Javaにおける型は、プリミティブ型、クラス型、配列型の3つに大別されます。また、値型と参照型の2つのカテゴリーに分けることもできます。

プリミティブ型 (Primitive Types)
プリミティブ型は、データそのものを格納します。Javaのプリミティブ型には、整数型(byte、short、int、long)、浮動小数点型(float、double)、論理型(boolean)、文字型(char)があります。これらの型は、プリミティブな値を直接的に格納し、メモリ上に確保されます。また、プリミティブ型は値型に分類されます。
クラス型 (Class Types)
クラス型は、オブジェクトへの参照を格納します。Javaでは、クラスやインタフェースを使用してユーザーが独自のデータ型を定義できます。これらの型は、ヒープ領域に実際のデータを格納し、変数はそのデータへの参照を保持します。クラス型は参照型に分類されます。
配列型 (Array Types)
配列型は、同じ型の複数の要素を格納します。Javaの配列はオブジェクトであり、配列型変数は配列への参照を保持します。配列は固定長ですが、可変長リストとして振る舞うコレクションクラスも提供されています。配列型も参照型に分類されます。
値型 (Value Types)
プリミティブ型は値型に分類されます。値型は、その変数が実際のデータの値を直接的に保持します。
参照型 (Reference Types)
クラス型と配列型は参照型に分類されます。参照型は、変数が実際のデータへの参照を保持し、そのデータはヒープ領域に格納されます。

プリミティブ型[編集]

Wikipedia
Wikipedia
ウィキペディアプリミティブ型の記事があります。

プリミティブ型は、Javaの基本的なデータ型で、値そのものを格納する値型です。

Javaのプリミティブ型には、以下の8つがあります。

プリミティブ型
データ型 サイズ (ビット数) 値の範囲 ラッパークラス
boolean 1 true または false Boolean
byte 8 -128 から 127 Byte
short 16 -32768 から 32767 Short
int 32 -2147483648 から 2147483647 Integer
long 64 -9223372036854775808 から 9223372036854775807 Long
float 32 IEEE 754 単精度浮動小数点数 Float
double 64 IEEE 754 倍精度浮動小数点数 Double
char 16 UTF-16の16ビット分。charという名前だがサロゲートペアにより16ビットの範囲を超えたUnicodeについては、「その半分」を表現する Character

Javaでは自動的に型変換が行われる場合があります。例えば、int型とdouble型の演算を行うと、int型の値が自動的にdouble型に変換されます。

ただし、変換元の型よりも変換先の型が大きい場合、精度の低下や情報の欠落が発生する場合があるため、注意が必要です。

また、Javaのプリミティブ型には、各データ型のラッパークラスが用意されています。 ラッパークラスを使用することで、プリミティブ型をクラスとして扱えるようになります。 例えば、int型の場合はIntegerクラスが対応しています。

参照型[編集]

Wikipedia
Wikipedia
ウィキペディア参照型の記事があります。

参照型には、クラス型、インタフェース型、配列型などがあります。 クラス型やインタフェース型は、それぞれ自分で定義して使用することができます。 配列型は、同じデータ型の値を複数格納するためのもので、以下のように宣言します。

注意点

Javaのプリミティブ型は、値そのものを格納するのに対し、参照型はオブジェクトへの参照を格納するため、メモリの使用方法が異なります。 また、プリミティブ型は値渡し、参照型は参照渡しとして扱われます。 このため、値渡しの場合は、値そのものがコピーされ、オリジナルの変数に影響を与えませんが、参照渡しの場合は、オブジェクトそのものへの参照が渡されるため、オリジナルのオブジェクトに影響を与える可能性があります。

リテラル[編集]

Wikipedia
Wikipedia
ウィキペディアリテラルの記事があります。

リテラル(Literal)とは、プログラミング言語において、コード内で直接値を表現する方法のことです。リテラルは、そのままの値を表し、プログラムの実行時にその値がそのまま使用されます。

プログラミング言語にはさまざまなタイプのリテラルがあります。以下にいくつかの例を挙げます。

  1. 整数リテラル: 整数の値を直接表現します。例えば、123, 0, -42などが整数リテラルです。
  2. 浮動小数点数リテラル: 浮動小数点数の値を直接表現します。例えば、3.14, 0.0, -1.5などが浮動小数点数リテラルです。
  3. 文字列リテラル: 文字列の値を直接表現します。文字列リテラルは通常、引用符('または")で囲まれます。例えば、"Hello, World!", 'a', "123"などが文字列リテラルです。
  4. 真偽値リテラル: 真偽値(真または偽)を直接表現します。例えば、truefalseが真偽値リテラルです。
  5. 特殊なリテラル: 一部のプログラミング言語には、特殊なリテラルが存在します。例えば、nullリテラルは、何も値がないことを表現します。

リテラルは、プログラムのコード内で値を明示的に表現するために使用されます。例えば、変数に値を代入する際や関数の引数として値を渡す際などに、リテラルを使用することが一般的です。

Javaにおけるリテラル[編集]

Javaにおけるリテラル(literal)とは、ソースコード上で直接的に表現される値のことを指します。つまり、コード内に直接書かれた値そのものを指します。

public class NumberLiteralExample {

    public static void main(String[] args) {
        // 10進数の整数リテラル
        int decimalInteger = 42;

        // 2進数の整数リテラル
        int binaryInteger = 0b101010; // 10進数の42

        // 8進数の整数リテラル
        int octalInteger = 052; // 10進数の42

        // 16進数の整数リテラル
        int hexInteger = 0x2A; // 10進数の42

        // 浮動小数点数リテラル
        double realNumber = 3.14;

        // 指数表記の浮動小数点数リテラル
        double scientificNotation = 6.022e23; // 6.022 × 10^23

        // 文字リテラル: 'A'を文字型の変数に代入
        char charValue = 'A';

        // 文字列リテラル: "Hello, World!"を文字列型の変数に代入
        String stringValue = "Hello, World!";

        // 真偽値リテラル: falseを真偽値型の変数に代入
        boolean booleanValue0 = false;

        // 真偽値リテラル: trueを真偽値型の変数に代入
        boolean booleanValue1 = true;

        // nullリテラル: nullをオブジェクト型の変数に代入
        Object nullValue = null;
    }
}

数値リテラルの中のアンダースコア[編集]

プログラミングにおける数値リテラルの中のアンダースコアは、数値を区切るために使用される特殊な記号です。この機能は、主に可読性を向上させるために導入されています。

大きな数値や複雑な数値を表す際に、アンダースコアを使用して数値をグループ化することで、コードがより見やすくなります。これにより、数値の桁を簡単に識別しやすくなります。

具体的には、以下のような場面でアンダースコアが使用されます。

  1. 整数リテラル: 例えば、1_000_000というように、大きな整数を区切る場合に使用されます。
  2. 浮動小数点数リテラル: 例えば、3.14_15というように、浮動小数点数を区切る場合に使用されます。
  3. バイナリリテラル: 例えば、0b1101_1010_0110のように、バイナリリテラルを区切る場合に使用されます。

アンダースコアは、数値リテラルの中で連続して使用することができますが、数値の先頭や末尾、小数点の前後、およびリテラルの接頭辞または接尾辞の直前に配置することはできません。また、プログラミング言語によってはアンダースコアの使用が制限される場合がありますので、言語の仕様に従って使用する必要があります。

Javaにおける数値リテラルの中のアンダースコア[編集]

Javaにおける数値リテラルの中のアンダースコアは、数値を区切るために使用される特殊な記号です。Javaでは、整数や浮動小数点数のリテラル内でアンダースコアを使用して、数値をグループ化することができます。これにより、数値の桁を視覚的に分けることができ、可読性が向上します。

以下に、Javaにおける数値リテラルの中のアンダースコアの使用例を示します。

  1. 整数リテラル:
    int million = 1_000_000;
    long creditCardNumber = 1234_5678_9012_3456L;
    int binaryNumber = 0b1101_1010_0110;
    
  2. 浮動小数点数リテラル:
    float pi = 3.14_15F;
    double bigNumber = 1_000_000.123_456;
    

アンダースコア(_)は、数値の先頭や末尾、小数点の前後、およびリテラルの接頭辞または接尾辞の直前に配置することができます。ただし、連続したアンダースコアや数値の先頭や末尾にアンダースコアを配置することはできません。また、アンダースコアを使用することで数値の値は変わりませんが、コードの可読性が向上します。

JEP 213[編集]

Java Enhancement Proposal(JEP)は、Javaプラットフォームおよび言語の改善提案をドキュメント化するためのフォーマットです。数値リテラル内のアンダースコアに関連するJEPは、「JEP 213: Milling Project Coin」です。

JEP 213は、Java 7のリリースで導入されました。このJEPの目的は、Java言語のシンプルな機能を向上させることで、コードの可読性と生産性を向上させることでした。その一環として、整数リテラルおよび浮動小数点数リテラル内でのアンダースコアの使用が導入されました。

アンダースコアを使用することで、大きな数値や複雑な数値をより読みやすくすることができるようになりました。この機能は、プログラムのメンテナンスやデバッグの際に特に有用です。

JEP 213の提案として、アンダースコアを使用した数値リテラルの改善が行われ、Javaのコードの可読性が向上しました。

null[編集]

プログラミングにおける「null」とは、値が存在しないことを表す特別な値です。nullはプログラムで使用されるさまざまなデータ型(オブジェクト、配列、ポインタなど)の初期値として設定されることがあります。

主な用途としては以下のようなものがあります:

  1. 値の不在を表現する: 変数が値を持たないことを示すために使用されます。例えば、ある関数が特定の条件下で値を返さない場合、通常はnullを返します。
  2. 初期化: 変数を初期化するために使用されることがあります。特に、オブジェクトや参照型の変数はnullで初期化されることがあります。
  3. オブジェクトの欠落を示す: オブジェクトが存在しないことを示すために使用されることがあります。例えば、あるオブジェクトのメンバー変数がnullであれば、そのオブジェクトが特定の状態にないことを意味することができます。

nullは便利な概念ですが、誤った使用やnullポインター例外などのランタイムエラーを引き起こす可能性があります。そのため、nullの使用は慎重に行う必要があります。近年のプログラミング言語では、null安全性を向上させるためにオプショナル型やnull許容型などの機能が導入されています。

Javaにおけるnull[編集]

Javaにおける「null」とは、参照型(Reference Type)の変数が参照するオブジェクトが存在しないことを示す特別な値です。Javaのすべてのオブジェクトはヒープ領域に保存され、変数はそのオブジェクトへの参照(アドレス)を保持します。nullは、そのような参照がオブジェクトを指していないことを示します。

以下はnullの主な特徴です:

  1. オブジェクトの不在を示す: 変数がnullを持っている場合、その変数がどのオブジェクトも指していないことを意味します。つまり、その変数には有効な値が含まれていないということです。
  2. 参照型の初期値: 参照型の変数はデフォルトでnullに初期化されます。つまり、明示的に値を設定しない限り、参照型の変数はnullを持ちます。
    String str; // strはnullを持つ
    
  3. NullPointerException(NPE): nullへの参照を解決しようとすると、NullPointerExceptionが発生する可能性があります。つまり、nullが予期せずプログラムの実行中に使用されるとエラーが発生します。

Javaでは、nullを適切に扱うことが重要です。nullをチェックし、nullポインターエクセプションを防ぐための適切な手段があります。 例えば、条件付きのnullチェックやOptionalクラスの使用などが挙げられます。 Javaにはnull安全性を向上させるためのさまざまな手段があり、プログラマーはこれらの手段を活用してnull関連の問題を回避できます。

NULL許容型[編集]

NULL許容型(nullable type)は、プログラミング言語において、変数が値を持たないことを明示的に許容する型のことです。通常、NULL許容型は、値が存在しないことを示すために特別な値(通常はNULL、nil、またはundefinedなど)を持ちます。

NULL許容型の主な目的は、nullポインタ例外などのランタイムエラーを回避し、プログラムの安全性を向上させることです。これにより、プログラマーは値が存在しない場合に備えて適切にコードを記述することができます。

多くのプログラミング言語でNULL許容型がサポートされています。例えば、JavaのOptional型、SwiftのOptional型、C#のNullable型などがあります。これらの型は、値が存在しない場合を明示的に示すことで、コードの安全性と可読性を向上させます。

以下は、各プログラミング言語におけるNULL許容型の例です:

各プログラミング言語におけるNULL許容型の例
言語 説明
Optional<T> Java JavaのOptional型は、値が存在しない場合にnullではなくOptional.empty()を返すため、nullポインタ例外を回避し、コードの安全性を向上させます。
Type? Kotlin KotlinのNullable型は、変数やプロパティの型の末尾に "?" を付けることで、その変数やプロパティがnullを許容するNullable型として扱われます。
Option<T> Scala ScalaのOption型は、Some値を持つ場合は値が存在し、Noneを持つ場合は値が存在しないことを示します。これにより、nullチェックやnullポインタ例外を回避することができます。
Nullable<T> C# C#のNullable型は、値型にnullを割り当てるための型です。通常の値型ではnullを許可しないため、Nullable型を使用することでnull許容型を表現します。
Option<T> Swift SwiftのOptional型は、値が存在する場合はSome値を持ち、値が存在しない場合はnilを持ちます。これにより、nilチェックやnilによるクラッシュを回避するために使用されます。

Optional[編集]

JavaのOptionalは、Java 8で導入されたクラスで、nullセキュリティという問題に対処するための手段の1つです。Optionalは、値が存在するかどうかを示すラッパークラスであり、nullを明示的に処理することなく、値の有無を安全に操作するための手段を提供します。

Optionalは以下のように使用できます:

  1. Optionalの作成: Optional.ofNullable() メソッドを使用して、可能性のあるnull値を含むオブジェクトからOptionalを作成できます。
    String str = null;
    Optional<String> optionalStr = Optional.ofNullable(str);
    
  2. 値の取得: 値が存在する場合、Optional.get() メソッドを使用してその値を取得できます。ただし、値が存在しない場合は NoSuchElementException がスローされる可能性がありますので、Optional.isPresent() メソッドを使用して事前に値の存在を確認することが重要です。
    if (optionalStr.isPresent()) {
        String value = optionalStr.get();
        System.out.println("Value: " + value);
    } else {
        System.out.println("Value is not present.");
    }
    
  3. 値の存在確認とデフォルト値の提供: 値が存在しない場合にデフォルト値を提供する場合は、Optional.orElse() メソッドを使用できます。
    String valueOrDefault = optionalStr.orElse("Default Value");
    
  4. 値の存在確認と値の処理: 値が存在する場合のみ、値に対して処理を行いたい場合は、Optional.ifPresent() メソッドを使用できます。
    optionalStr.ifPresent(value -> System.out.println("Value: " + value));
    

Optionalは、null値の扱いに関するバグを減らし、より安全で明確なコードを作成するのに役立ちます。 ただし、Optionalを過度に使用することは、コードを複雑にする可能性があるため、適切なバランスが必要です。

以下は、JavaのOptionalクラスの一部の主要なメソッドとその説明を表形式で示したものです。

Optionalクラスの主要なメソッド一覧
メソッド 説明
empty() 空のOptionalインスタンスを作成します。
of(T value) 指定された非nullの値でOptionalインスタンスを作成します。
ofNullable(T value) 指定された値がnullであれば空のOptional、そうでなければその値でOptionalインスタンスを作成します。
isPresent() Optionalに値が含まれている場合はtrueを返します。
ifPresent(Consumer<? super T> consumer) Optionalが値を含んでいる場合、指定されたコンシューマー関数を値に適用します。
get() 値を取得します。値が存在しない場合は例外NoSuchElementExceptionをスローします。
orElse(T other) 値が存在する場合はその値を返し、そうでなければ指定された値を返します。
orElseGet(Supplier<? extends T> supplier) 値が存在する場合はその値を返し、そうでなければサプライヤー関数の結果を返します。
orElseThrow(Supplier<? extends X> exceptionSupplier) 値が存在する場合はその値を返し、そうでなければ指定された例外をスローします。
filter(Predicate<? super T> predicate) 値が述語によってテストされ、述語がtrueを返した場合はこのOptionalを返します。それ以外の場合は空のOptionalを返します。
map(Function<? super T, ? extends U> mapper) 値を関数に適用し、結果が非nullであればそれを含むOptionalを返します。そうでなければ空のOptionalを返します。
flatMap(Function<? super T, Optional<U>> mapper) 値を関数に適用し、結果が空のOptionalでない場合はそのOptionalを返します。そうでなければ空のOptionalを返します。
equals(Object obj) 指定されたオブジェクトがこのOptionalと等しいかどうかを比較します。
hashCode() Optionalのハッシュコード値を返します。
toString() Optionalの文字列表現を返します。

これらのメソッドは、Java 8からOptionalクラスで導入され、nullを避けるために便利な方法を提供します。

Optionalが出来ても、参照型はnullを取り得る[編集]

Optionalはnullを扱う際の安全性を向上させるための手段ですが、参照型には依然としてnullを取り得るという点に留意する必要があります。

Optionalは、主にnullを返す可能性のあるメソッドの戻り値や、メソッドの引数として使用されます。しかし、既存のコードや外部ライブラリとの連携、あるいは一時的なnull値の許容など、様々な理由でnullが依然として存在することがあります。

そのため、Optionalを使用することでnullの扱いを明確にすることができますが、すべてのnullを完全に排除することは難しい場合があります。したがって、プログラマーは依然としてnullの可能性に備えてコードを記述する必要があります。

文字列[編集]

プログラミングにおける文字列(String)は、文字の連続した列を表すデータ型です。文字列は、テキストや文字データを扱うための基本的なデータ構造であり、多くのプログラミング言語でサポートされています。

文字列は、文字の配列として表現されます。各文字は、通常はUnicodeやASCIIなどの文字コードで符号化され、文字列全体はそれらの文字の連続したシーケンスとして表現されます。 文字列は、プログラム内でテキストデータを格納、操作、表示するために使用されます。

具体的な用途としては、次のようなものがあります:

  1. テキストの処理: 文字列を使用して、ユーザーからの入力や外部ファイルから読み取ったテキストデータを処理します。例えば、テキストの検索、置換、分割などの操作を行います。
  2. 表示とフォーマット: 文字列は、プログラムの出力として表示されるテキストを表します。フォーマット済みのテキストや、可変のテキストメッセージを生成してユーザーに表示するために使用されます。
  3. データの保存: 文字列は、データベースやファイルなどの永続的なストレージに保存されるテキストデータを表現するために使用されます。例えば、ユーザーの名前やメールアドレスなどの情報を文字列として保存します。
  4. プログラムの制御: 文字列は、条件分岐やループなどのプログラムの制御構造においても使用されます。特定の文字列のパターンに一致するかどうかを確認するための条件式や、繰り返し処理の終了条件として使用されます。

文字列は、ほぼすべてのプログラミング言語で重要な概念であり、プログラミングにおいて広く使用されています。

Javaの文字列[編集]

Javaの文字列は、java.lang.Stringクラスで表されるオブジェクト型のデータです。文字列は、文字のシーケンスであり、文字列中の各文字はUnicode文字を表します。Javaの文字列はイミュータブル(不変)であり、一度作成された文字列オブジェクトの内容は変更できません。

以下は、Javaの文字列に関する基本的な操作を1つのソースコードにまとめたものです。

public class StringQuickTour {
    public static void main(String[] args) {
        // 文字列の作成
        String str1 = "Hello";
        String str2 = new String("World");

        // 文字列の結合
        String result = str1 + " " + str2;

        // 文字列の長さ
        int length = str1.length();

        // 文字の取得
        char firstChar = str1.charAt(0);

        // 部分文字列の取得
        String subStr = str1.substring(1, 3);

        // 文字列の比較
        boolean isEqual = str1.equals(str2);

        // 文字列の検索
        int index = str1.indexOf("l");

        // 大文字・小文字変換
        String upperCaseStr = str1.toUpperCase();
        String lowerCaseStr = str1.toLowerCase();

        // 空白の削除
        String trimmedStr = str1.trim();

        // 文字列の置換
        String replacedStr = str1.replace("l", "r");

        // 結果の表示
        System.out.println("Result: " + result);
        System.out.println("Length: " + length);
        System.out.println("First character: " + firstChar);
        System.out.println("Substring: " + subStr);
        System.out.println("Equal: " + isEqual);
        System.out.println("Index of 'l': " + index);
        System.out.println("Uppercase: " + upperCaseStr);
        System.out.println("Lowercase: " + lowerCaseStr);
        System.out.println("Trimmed: " + trimmedStr);
        System.out.println("Replaced: " + replacedStr);
    }
}

このコードでは、文字列の作成、結合、長さの取得、部分文字列の取得、比較、検索、大文字・小文字変換、空白の削除、置換などの基本的な操作を行っています。これらの操作は、Javaの文字列処理においてよく使用されます。

メソッド[編集]

以下は、Javaの文字列クラス (java.lang.String) に含まれる主なメソッドの一覧です。

文字列のメソッド一覧
メソッド 説明
charAt(int index) 指定されたインデックスの文字を取得します。
length() 文字列の長さを取得します。
substring(int beginIndex) 指定されたインデックスから文字列の終端までの部分文字列を取得します。
substring(int beginIndex, int endIndex) 指定された範囲の部分文字列を取得します。
indexOf(String str) 指定された文字列が最初に出現する位置のインデックスを取得します。
lastIndexOf(String str) 指定された文字列が最後に出現する位置のインデックスを取得します。
startsWith(String prefix) 指定された文字列で始まるかどうかを判定します。
endsWith(String suffix) 指定された文字列で終わるかどうかを判定します。
toLowerCase() 文字列を小文字に変換します。
toUpperCase() 文字列を大文字に変換します。
trim() 文字列の先頭および末尾の空白を除去します。
equals(Object another) 指定されたオブジェクトと文字列が等しいかどうかを判定します。
equalsIgnoreCase(String another) 大文字と小文字を無視して、指定された文字列と等しいかどうかを判定します。
compareTo(String another) 2つの文字列を辞書順で比較します。
concat(String str) 指定された文字列を現在の文字列の末尾に追加します。
replace(char oldChar, char newChar) 指定された古い文字を新しい文字で置き換えます。
replaceAll(String regex, String replacement) 正規表現にマッチする部分を、指定された置換文字列で置き換えます。
split(String regex) 指定された正規表現に基づいて、文字列を分割します。
contains(CharSequence s) 指定された文字列または文字シーケンスがこの文字列内に含まれているかどうかを判定します。

これらのメソッドは、Javaの文字列を操作するために使用されます。それぞれのメソッドは、文字列に対して特定の操作を行います。

配列[編集]

プログラミングにおける配列(Array)は、同じデータ型の要素が連続して格納されたデータ構造です。配列は、複数の値を一つの変数に格納するために使用され、要素はインデックス(通常は0から始まる整数)によって識別されます。配列は、データの集合を表現し、効率的なデータアクセスと操作を可能にします。

配列は、以下のような特性を持ちます:

  1. 同じデータ型の要素: 配列内のすべての要素は同じデータ型である必要があります。例えば、すべての要素が整数、文字列、または浮動小数点数などの特定の型である必要があります。
  2. 連続したメモリ領域に配置される: 配列の要素はメモリ内で連続した領域に配置されます。これにより、配列内の要素は互いに隣接しているため、効率的なデータアクセスが可能になります。
  3. 要素のインデックス: 配列内の要素はインデックスによって識別されます。通常は0から始まる整数のインデックスが使用され、各要素はそのインデックスによってアクセスされます。
  4. サイズ固定: 配列は固定サイズであり、作成後に要素の数を変更することはできません。一度に格納できる要素の数が決まっています。

配列は、プログラム内で複数の値を効率的に処理するために広く使用されます。特定の要素を参照、更新、追加、削除することができ、ループ構造を使用して配列内のすべての要素を順番に処理することができます。多くのプログラミング言語で配列がサポートされており、基本的なデータ構造の一つとして広く使用されています。

Javaの配列[編集]

Javaの配列は、同じ型の複数の要素を格納するためのデータ構造です。 配列は固定サイズであり、要素は0から始まるインデックスでアクセスされます。 Javaでは、配列はオブジェクトとして扱われます。

以下のJavaのソースコードは、配列を宣言し、初期化し、要素へのアクセス、配列の長さの取得、拡張forループの使用、配列のコピー、ソート、比較など、様々な操作を行う方法を示しています。

import java.util.Arrays;

public class ArrayQuickTour {
    public static void main(String[] args) {
        // 配列の宣言と初期化
        int[] numbers = {5, 2, 7, 1, 9};

        // 配列の要素へのアクセス
        System.out.println("First element: " + numbers[0]);

        // 配列の長さの取得
        int length = numbers.length;
        System.out.println("Array length: " + length);

        // 拡張forループを使って配列の要素にアクセス
        System.out.println("Elements:");
        for (int num : numbers) {
            System.out.println(num);
        }

        // 配列のコピー
        int[] copy = Arrays.copyOf(numbers, numbers.length);
        System.out.println("Copied array: " + Arrays.toString(copy));

        // 配列のソート
        Arrays.sort(numbers);
        System.out.println("Sorted array: " + Arrays.toString(numbers));

        // 配列の比較
        int[] numbers2 = {5, 2, 7, 1, 9};
        boolean isEqual = Arrays.equals(numbers, numbers2);
        System.out.println("Arrays are equal: " + isEqual);
    }
}

このコードでは、配列を宣言し、初期化する際に初期化リストを使用しています。そして、配列の要素へのアクセス、配列の長さの取得、拡張forループを使った要素の表示、Arrays.copyOfを使った配列のコピー、Arrays.sortを使った配列のソート、そしてArrays.equalsを使った配列の比較を行っています。

このコードは、配列を操作するための基本的な手法を示しており、これらの手法を理解することで、Javaで配列を効果的に利用することができます。

メソッド一覧[編集]

以下は、Javaの配列で使用できる主なメソッドの一覧です。この一覧には、配列の作成、要素の操作、配列のコピー、比較、ソートなど、さまざまな操作に関連するメソッドが含まれています。

配列のメソッド一覧
メソッド 説明
copyOf() 配列のコピーを作成します。指定した長さよりも短い場合は、ゼロパディングされ、指定した長さよりも長い場合は、切り詰められます。
copyOfRange() 指定された範囲の配列のコピーを作成します。
equals() 2つの配列が同じかどうかを比較します。
fill() 配列のすべての要素を指定した値で埋めます。
sort() 配列の要素を昇順にソートします。
binarySearch() 二分探索を使用して、指定された値を配列内で検索します。ソートされている配列で使用する必要があります。
toString() 配列の内容を文字列として返します。
hashCode() 配列のハッシュコードを返します。
parallelPrefix() 並列で累積を計算し、結果を配列に格納します。
parallelSetAll() 配列のすべての要素に対して、指定された関数を並列で適用します。
parallelSort() 配列の要素を並列にソートします。
setAll() 配列のすべての要素に対して、指定された関数を適用します。
stream() 配列をストリームに変換します。
asList() 配列を固定サイズのリストに変換します。
hashCode() 配列のハッシュコードを返します。

これらのメソッドは、Javaの java.util.Arrays クラスで定義されており、配列を効果的に操作するための便利なユーティリティを提供しています。

多次元配列[編集]

Javaにおける多次元配列(Multidimensional Array)は、配列の要素が配列である配列のことを指します。つまり、配列内に配列を持つことで、複数の次元を持つデータ構造を表現します。

たとえば、2次元配列は行と列のような2つの次元を持ちます。3次元配列は、立方体のように3つの次元を持ちます。これにより、行列、立方体、テンソルなどの構造化されたデータを効率的に表現することができます。

以下は、Javaで多次元配列を宣言および初期化する方法の例です。

// 2次元配列の宣言と初期化
int[][] twoDimArray = new int[3][4]; // 3行4列の2次元配列
twoDimArray[0][0] = 1; // (0, 0)に値を設定
twoDimArray[1][2] = 5; // (1, 2)に値を設定

// 3次元配列の宣言と初期化
int[][][] threeDimArray = new int[2][3][4]; // 2*3*4の3次元配列
threeDimArray[0][1][2] = 7; // (0, 1, 2)に値を設定
threeDimArray[1][2][3] = 9; // (1, 2, 3)に値を設定

多次元配列は、ネストされたforループを使用して要素にアクセスすることが一般的です。例えば、2次元配列の要素にアクセスするには、2つのループを使用して行と列を反復処理します。

for (int i = 0; i < twoDimArray.length; i++) {
    for (int j = 0; j < twoDimArray[i].length; j++) {
        System.out.print(twoDimArray[i][j] + " ");
    }
    System.out.println();
}

Java 5以降では、拡張forループ(enhanced for loop)またはfor-eachループと呼ばれる新しいループ形式が導入されました。これは、コレクションや配列などの反復可能なオブジェクトを簡潔に反復処理するために使用されます。

以下は、拡張forループを使用して多次元配列を反復処理する方法の例です。

// 2次元配列の反復処理
for (int[] row : twoDimArray) {
    for (int element : row) {
        System.out.print(element + " ");
    }
    System.out.println();
}

// 3次元配列の反復処理
for (int[][] plane : threeDimArray) {
    for (int[] row : plane) {
        for (int element : row) {
            System.out.print(element + " ");
        }
        System.out.println();
    }
}

この方法では、2つまたは3つのネストされたループを使用する必要がなくなり、より簡潔で読みやすいコードが得られます。各ループでは、拡張forループを使用して配列の各要素を直接取得し、それを処理することができます。

拡張forループは、配列やリストなどの反復可能なコレクションの要素を処理する場合に非常に便利です。これにより、ループの記述が簡素化され、コードの可読性が向上します。

以下は、4x4のdouble配列を宣言し、それを単位行列にするJavaのコード例です。

public class Main {
    public static void main(String[] args) {
        // 4x4のdouble配列を宣言し、単位行列に初期化する
        int size = 4;
        double[][] matrix = new double[size][size];
        
        // 単位行列に初期化する
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[i].length; j++) {
                matrix[i][j] = (i == j) ? 1.0 : 0.0;
            }
        }
        
        // 行列を出力する
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[i].length; j++) {
                System.out.print(matrix[i][j] + " ");
            }
            System.out.println();
        }
    }
}

このコードは、4x4のdouble配列を宣言し、その要素を単位行列に初期化します。その後、単位行列を出力します。単位行列は、対角要素がすべて1で、それ以外の要素がすべて0の正方行列です。

多次元配列は、行列や画像処理など、多次元のデータを扱う際に役立ちます。

コレクション[編集]

プログラミングにおけるコレクション(Collection)は、複数の要素をまとめて管理するためのデータ構造です。コレクションは、配列やリスト、セット、マップなど、さまざまな形式で提供されます。これらのデータ構造は、異なる目的や要件に応じて使われ、データの格納、検索、操作、管理を行うための便利な手段として利用されます。

コレクションの主な特徴は以下の通りです:

  1. 動的サイズ: コレクションは通常、要素の追加や削除などの操作によって動的にサイズが変化します。配列のように固定サイズではなく、必要に応じて要素を増減させることができます。
  2. ジェネリック: 多くの場合、コレクションはジェネリック型をサポートしており、異なるデータ型の要素を格納することができます。これにより、汎用的なコレクションを作成し、様々な種類のデータを扱うことが可能になります。
  3. 高度な操作: コレクションは、要素の追加、削除、検索、ソート、フィルタリングなど、さまざまな操作をサポートします。これにより、効率的なデータの管理や処理が可能になります。
  4. 相互変換: コレクション間でデータを相互変換することができる場合があります。たとえば、配列をリストに変換したり、リストをセットに変換したりすることができます。

プログラミングにおけるコレクションは、さまざまな用途に活用されます。例えば、データの一時的な保存や処理、データの集計や集合演算、データの操作や変換など、さまざまな場面で利用されます。多くのプログラミング言語やフレームワークは、標準ライブラリやサードパーティライブラリを通じてさまざまなコレクションを提供しています。

Javaのコレクション[編集]

Javaのコレクションは、複数の要素を格納し、効率的なデータ操作を可能にするためのフレームワークです。Javaのコレクションフレームワークは、java.utilパッケージに含まれており、さまざまなインターフェースとそれらを実装するクラスが提供されています。主なコレクションインターフェースには、リスト、セット、マップなどがあります。

以下は、Javaのコレクションフレームワークを使った例を1つのソースコードにまとめたものです。

import java.util.*;

public class CollectionQuickTour {
    public static void main(String[] args) {
        // リストの例
        List<String> myList = new ArrayList<>();
        myList.add("Apple");
        myList.add("Banana");
        myList.add("Orange");
        System.out.println("List: " + myList);

        // セットの例
        Set<Integer> mySet = new HashSet<>();
        mySet.add(1);
        mySet.add(2);
        mySet.add(3);
        mySet.add(1); // 重複した要素は無視される
        System.out.println("Set: " + mySet);

        // マップの例
        Map<String, Integer> myMap = new HashMap<>();
        myMap.put("One", 1);
        myMap.put("Two", 2);
        myMap.put("Three", 3);
        System.out.println("Map: " + myMap);

        // キューの例
        Queue<String> myQueue = new LinkedList<>();
        myQueue.add("First");
        myQueue.add("Second");
        myQueue.add("Third");
        System.out.println("Queue: " + myQueue);

        // デッキの例
        Deque<Integer> myDeque = new ArrayDeque<>();
        myDeque.addFirst(1);
        myDeque.addLast(2);
        myDeque.addLast(3);
        System.out.println("Deque: " + myDeque);
    }
}

このコードでは、リスト、セット、マップ、キュー、デッキのそれぞれのコレクションを作成し、要素を追加しています。それぞれのコレクションの要素が出力されます。これにより、Javaのコレクションフレームワークの基本的な使い方を示しています。

以下は、Javaのコレクションフレームワークに含まれる主要なクラスとインターフェースの一覧を、名前、クラス・インターフェースの別、説明の順に表組みで示したものです。

コレクションフレームワークに含まれる主要なクラスとインターフェース一覧
名前 クラス・インターフェースの別 説明
Collection インターフェース オブジェクトのコレクションを表します。リスト、セット、キューなどの基本的な操作を提供します。
List インターフェース 順序付きの要素のコレクションを表します。要素の重複を許します。
Set インターフェース 重複を許さない要素のコレクションを表します。
Map インターフェース キーと値のペアのコレクションを表します。キーは一意であり、各キーには1つの値が関連付けられます。
Queue インターフェース FIFO (First-In-First-Out) データ構造を表します。要素の挿入はキューの末尾に行われ、削除はキューの先頭から行われます。
Deque インターフェース 双方向キュー (Double Ended Queue) データ構造を表します。要素の挿入と削除がキューの両端で行われます。
ArrayList クラス 動的配列を実装したリストです。
LinkedList クラス リンクリストを実装したリストです。
HashSet クラス ハッシュテーブルを使用して実装されたセットです。
TreeSet クラス 赤黒木を使用して実装されたセットです。要素は自然順序またはコンパレータによってソートされます。
LinkedHashSet クラス ハッシュテーブルとリンクリストを組み合わせて実装されたセットです。要素の挿入順序を保持します。
HashMap クラス ハッシュテーブルを使用して実装されたマップです。
TreeMap クラス 赤黒木を使用して実装されたマップです。キーは自然順序またはコンパレータによってソートされます。
LinkedHashMap クラス ハッシュテーブルと双方向リンクリストを組み合わせて実装されたマップです。要素の挿入順序を保持します。

これらのクラスとインターフェースは、Javaのコレクションフレームワークを構成し、さまざまなデータ構造を効率的に操作するための手段を提供します。

コレクションフレームワーク[編集]

Javaのコレクションフレームワークは、データを効率的に管理し、操作するための標準的なAPIセットです。これにより、プログラマーはリスト、セット、マップなどのさまざまなデータ構造を使用してデータを格納し、操作することができます。Javaのコレクションフレームワークは、java.utilパッケージに含まれており、多くのインターフェースとクラスから構成されています。

コレクションフレームワークの主な特徴は次のとおりです:

  1. 柔軟性: コレクションフレームワークは、異なる種類のデータ構造を提供し、プログラマーがプログラムの要件に応じて適切なデータ構造を選択できるようにします。
  2. 再利用性: 既存のコレクションクラスやインターフェースを使用することで、プログラマーは再利用可能なコードを作成しやすくなります。
  3. 拡張性: コレクションフレームワークは、カスタムコレクションの作成や既存のコレクションの拡張を容易にします。プログラマーは独自のデータ構造を定義し、それをコレクションとして使用することができます。
  4. 効率性: コレクションフレームワークは、データの効率的な格納、検索、操作を実現するために最適化されています。さまざまなデータ構造は、特定の操作に対して最適な性能を提供します。
  5. 型安全性: ジェネリクスを使用することで、コンパイル時の型安全性が向上します。これにより、コンパイル時に型エラーを検出しやすくなります。

コレクションフレームワークは、Javaプログラミングにおいて非常に重要であり、さまざまなアプリケーションやライブラリで広く使用されています。プログラマーは、これらのAPIを十分に理解し、適切に活用することで、効率的で堅牢なコードを作成することができます。

クラス[編集]

プログラミングにおけるクラスは、オブジェクト指向プログラミングの中核をなす概念であり、データとそのデータを操作する関数(メソッド)を組み合わせたものです。クラスは、特定のデータ構造や振る舞いを定義し、それをインスタンス化して実際のオブジェクトを作成します。

Javaにおけるクラス[編集]

Javaにおけるクラスは、オブジェクト指向プログラミング(OOP)の中心的な概念であり、属性(フィールド)と操作(メソッド)を組み合わせた設計図です。クラスは、特定のオブジェクトの構造や振る舞いを定義し、その設計に基づいて実際のオブジェクトを作成します。Javaのクラスは、コンストラクタを使用して新しいオブジェクトを生成し、インスタンス変数を使用してオブジェクトの状態を保持します。また、メソッドを使用してオブジェクトの振る舞いを定義し、それらのメソッドを呼び出してオブジェクトの操作を実行します。クラスは、Javaプログラムの構造化と再利用性を高めるために使用され、大規模なアプリケーション開発において重要な役割を果たします。

クラスの宣言と構造[編集]

Javaでクラスを定義するには、以下のようにクラス名と中括弧で囲まれたクラス本体を宣言します。

public class MyClass {
    // フィールド(属性)
    int myField;

    // メソッド(動作)
    void myMethod() {
        // メソッドの中身
    }
}
  • public はアクセス修飾子で、このクラスが他のクラスからアクセス可能であることを示します。
  • class キーワードはクラスを宣言するために使用されます。
  • MyClass はクラスの名前です。
  • 中括弧 {} 内にはクラスのフィールドやメソッドが定義されます。

クラスのインスタンス化[編集]

クラスのインスタンス化は、クラスからオブジェクトを生成するプロセスです。

MyClass myObject = new MyClass();
  • new キーワードは新しいオブジェクトのインスタンスを作成します。
  • MyClass() はクラスのコンストラクタです。この場合、引数を取らないデフォルトのコンストラクタが使用されます。

フィールドとメソッドへのアクセス[編集]

myObject.myField = 10; // フィールドへのアクセス
myObject.myMethod();   // メソッドの呼び出し
  • .(ドット)演算子を使用して、オブジェクトのフィールドやメソッドにアクセスします。

クラスの利用[編集]

public class Main {
    public static void main(String[] args) {
        MyClass myObject = new MyClass();
        myObject.myField = 20;
        myObject.myMethod();
    }
}
  • main メソッドはJavaプログラムのエントリーポイントです。
  • MyClass の新しいインスタンスを作成し、フィールドに値を設定し、メソッドを呼び出しています。

これがJavaのクラスの基本的な概念です。クラスはオブジェクト指向プログラミングの中心的な要素であり、Javaプログラムの構築において重要な役割を果たします。

例外処理[編集]

プログラミングにおける例外処理は、プログラムが実行中に発生する予期しないエラーや異常な状況に対処するための仕組みや手法を指します。プログラムが実行中にエラーが発生する可能性がある場合、例外処理はプログラムの安定性を維持し、クラッシュや異常終了を防ぎます。

以下は、プログラミングにおける例外処理の基本的な概念です:

  1. 例外の発生: プログラムが実行中にエラーが発生すると、通常のプログラムのフローが中断されます。このような状況を例外と呼びます。例外は、ゼロ除算、配列の範囲外アクセス、ファイルが見つからないなどのさまざまな条件で発生します。
  2. 例外のスロー: プログラム内の特定の箇所で、例外が発生したことを明示的に示すことができます。この動作を例外のスローと呼びます。通常、特定の条件が満たされた場合やエラーが発生した場合に、例外をスローします。
  3. 例外のキャッチ: プログラム内で例外がスローされた場合、適切な処理を行うために例外をキャッチすることができます。この動作を例外のキャッチと呼びます。例外をキャッチすることで、プログラムは正常に処理を継続するか、エラーを適切に通知することができます。
  4. 例外ハンドリング: 例外をキャッチして処理する手法を例外ハンドリングと呼びます。例外ハンドリングでは、例外をキャッチし、エラーをログに記録したり、ユーザーにエラーメッセージを表示したり、プログラムの状態を回復させたりすることができます。

例外処理は、プログラミングにおいて非常に重要です。適切に実装された例外処理は、プログラムの安定性を高め、ユーザーエクスペリエンスを向上させるのに役立ちます。また、例外処理はデバッグや問題解決の際にも役立ちます。

Javaの例外処理[編集]

Javaの例外処理は、プログラム実行中に予期しない状況やエラーが発生した場合に、その状況を適切に処理するための仕組みです。Javaの例外処理は、プログラムの安全性や信頼性を高めるために非常に重要です。

例外は、実行時に発生するエラーの種類や条件を表します。例えば、ゼロ除算、配列の範囲外へのアクセス、ファイルが見つからないなどのエラーは、Javaの例外処理を使用して適切に処理することができます。

Javaの例外処理は以下のような特徴を持ちます:

  1. 例外クラスの階層構造: Javaでは、Throwable クラスを基底クラスとして、例外を表すさまざまなクラスが階層的に定義されています。Throwable クラスのサブクラスには、Exception(検査例外)や RuntimeException(非検査例外)などがあります。
  2. try-catch-finally ブロック: Javaでは、try ブロック内で例外が発生する可能性のあるコードを囲み、それに対する処理を catch ブロックで定義します。また、finally ブロックを使用して、例外の発生にかかわらず必ず実行される処理を記述することができます。
  3. 例外のスロー: メソッド内で発生した例外を明示的に処理せずに、呼び出し元に例外をスローすることができます。これにより、例外を適切な場所で処理することができます。
  4. 検査例外と非検査例外: Javaでは、検査例外(checked exception)と非検査例外(unchecked exception)の2種類の例外があります。検査例外はコンパイル時にチェックされるため、明示的に処理するか、メソッドの throws 宣言で伝播させる必要があります。一方、非検査例外は実行時に発生し、明示的な処理が必要ありません。

Javaの例外処理は、プログラムのロバストさを向上させ、予期しない状況に対処するための重要な手段です。例外処理を適切に使用することで、プログラムの安全性や信頼性を向上させることができます。

以下は、Javaの例外処理を1つのソースコードで解説したものです。

public class ExceptionHandlingQuickTour {
    public static void main(String[] args) {
        try {
            // 例外が発生する可能性のあるコード
            int result = divide(10, 0);
            System.out.println("結果: " + result); // この行は実行されません
        } catch (ArithmeticException e) {
            // ArithmeticException が発生した場合の処理
            System.out.println("0 で割ることはできません。");
        } finally {
            // 必ず実行されるブロック
            System.out.println("プログラムの実行が完了しました。");
        }
    }

    // 例外をスローする可能性のあるメソッド
    public static int divide(int num1, int num2) {
        if (num2 == 0) {
            throw new ArithmeticException("0 で割ることはできません。");
        }
        return num1 / num2;
    }
}

この例では、次のような内容を含んでいます:

  1. main メソッド内で try-catch-finally ブロックが使用されています。try ブロック内では例外が発生する可能性のあるコードが配置され、catch ブロックでは特定の例外が発生した場合の処理が定義されています。finally ブロックは例外の発生にかかわらず必ず実行されるブロックです。
  2. divide メソッドは、引数 num2 が 0 の場合に ArithmeticException をスローする可能性があります。
  3. main メソッドでは、divide メソッドを呼び出し、0 で割るエラーが発生した場合に ArithmeticException をキャッチし、適切なメッセージを出力します。
  4. finally ブロックは、プログラムが正常に終了したかどうかに関係なく、必ず実行されることが保証されています。

throws[編集]

Javaには throws キーワードがあります。throws キーワードは、メソッドが特定の例外をスローする可能性があることを宣言するために使用されます。

メソッドが特定の例外をスローする可能性がある場合、そのメソッドのシグネチャに throws キーワードを使用して、その例外を指定します。これにより、メソッドを呼び出す際に、呼び出し元がその例外を適切に処理するか、またはさらに上位の呼び出し元に例外を伝播させるかを決定できます。

例えば:

public void readFile() throws IOException {
    // ファイルを読み込む処理
}


この例では、readFile メソッドが IOException をスローする可能性があることが宣言されています。メソッド内で IOException が発生する可能性がある場合、その例外をキャッチして処理するか、または readFile メソッドの呼び出し元で try-catch ブロックを使用して例外を処理する必要があります。

throws キーワードを使用することで、メソッドの呼び出し元がそのメソッドがスローする可能性がある例外に対処できるようになります。

例外クラス[編集]

Javaの例外には、いくつかの主要なクラスがあります。

以下に、Javaの例外クラスのいくつかを表組みで示します。

主要な例外クラス
例外クラス 説明
ArithmeticException 数学的な操作中に発生する例外(ゼロ除算など)
ArrayIndexOutOfBoundsException 配列への無効なインデックスアクセスが発生した場合の例外
NullPointerException ヌル参照が使用された場合の例外
IOException 入出力操作中に発生する例外
FileNotFoundException ファイルが見つからない場合の例外
NumberFormatException 文字列が数値に変換できない場合の例外
IllegalArgumentException メソッドに渡された引数が無効な場合の例外
RuntimeException 実行時に発生する一般的な例外の基底クラス

これらはJavaの例外の一部であり、それぞれ特定の状況や条件で発生します。Javaの例外処理では、これらの例外クラスを適切にキャッチして処理することが重要です。また、必要に応じて独自の例外クラスを定義することもできます。