Javaの基本文法かなりざっくりまとめ

Java
Java

Java言語の基本的な文法についてかなりざっくりまとめました。
実装例+簡単な解説のみの構成となっています。

Javaの基本文法の確認やおさらいといった目的で読んでいただけたらと思っています。
右側の目次から確認したい項目へと飛んで読んでいってください。
Javaをこれから勉強される方でも、頭から通しで読んでいけばなんとなく書けるようになるかなとは思います。

ではさっそくいきましょう!

基礎構文

クラス定義

public class Main {
}

{アクセス修飾子} class {クラス名}でクラスを定義できます。
クラス名の後ろの中括弧{からそれに対応する閉じ括弧}までの中に書かれた要素がクラスの定義となります。

アクセス修飾子がpublicのクラスは、そのクラス名と一致する名前のJavaファイル内に定義されなければいけません。例えば、HogeHogeクラスはHogeHoge.javaで定義しないと、コンパイルエラーとなります。

様々なクラス定義の方法を一気にご紹介します。

// インターフェースの定義
public interface Main {
}

// Enumクラスの定義
public enum Main {
}

// 抽象クラスの定義
public abstract class Main {
}

// インターフェースの実装クラス
public class MainImpl implements Main {
}

// スーパークラスを継承
public class Main extends AbstractMain {
}

// 継承禁止クラスの定義
// クラス定義にfinalが指定されている場合、このクラスを継承したクラスを作成できなくなる
public final class Main {
}

// クラス定義の入れ子
public class Parent {
    // アクセス修飾子がprivateの場合、このクラスはParentクラスからのみ参照することができる
    private class Child {
    }
}

インターフェースやEnumについてもアクセス修飾子がpublicのものについては、その名前をファイル名と一致させる必要があります。

コンストラクタ

public class Main {
    public Main() {
        // コンストラクタの処理を記述
    }
}

コンストラクタは、クラスのインスタンスを生成するときに呼び出される、初期処理を定義するものです。
{アクセス修飾子} {クラス名}({引数の型} {引数名}) {で定義することができます。
コンストラクタ名はクラス名と同一にする必要があり、戻り値を返すことはできません。

様々なコンストラクタの定義の方法を一気に紹介します。

// コンストラクタには引数の指定が可能
// 引数のパターンが違えば複数のコンストラクタを定義可能
public class Main {
    public Main(String str) {
        System.out.println(str);
    }
    public Main(String str1, String str2) {
        System.out.println(str1);
        System.out.println(str2);
    }
}

// コンストラクタのアクセス修飾子をprivateとすることで
// 外部クラスからこのクラスをnewでインスタンス生成できないようにする
public class Main {
    private Main() {
    }
}

コンストラクタの定義は必須ではありません。定義しなかった場合は、引数がなく、(スーパークラスのコンストラクタを呼び出す以外は)何もしないデフォルトコンストラクタというものが自動的に作成されます。これを使用することで、コンストラクタが明示的に定義されていなくてもインスタンスを生成することができます。

メソッド

定義
public class Main {
    public void sayHello(String name) {
        System.out.println("Hello, " + name);
    }
}

メソッドは一連の処理の流れを定義するものです。
{アクセス修飾子} {戻り値の型} {メソッド名}({引数の型} {引数名}) {で定義することができます。
戻り値がない場合は、戻り値の型にvoidを指定します。

様々なメソッド定義の方法を一気に紹介します。

// 可変長引数
public void sayHello(String... name) {
    System.out.println("Hello, " + name[0]);
}

// staticメソッド
// インスタンスを生成しなくてもこの処理は呼び出すことができる。
public static void sayHello(String name) {
    System.out.println("Hello, " + name);
}

// オーバーライド禁止
public final void sayHello(String name) {
    System.out.println("Hello, " + name);
}

// インターフェースでのメソッド定義
public interface Main {
    // アクセス修飾子を省略できる。その場合、publicとなる。
    String greeting(String country);
}

// abstractメソッド
public abstract class AbstractMain {
    // アクセス修飾子を省略できない。
    protected abstract String greeting(String country);
}
呼び出し方
public static void main(String[] args) {
    String str = "あいうえお";
    String concatStr = str.concat("かきくけこ");

    System.out.println(concatStr); // あいうえおかきくけこ
}

{インスタンス変数}.{メソッド名}({引数})という書き方で、そのインスタンスが持つメソッドを呼び出すことができます。変数が戻り値を返す場合は、=を使ってその値を変数に代入することができます。

staticメソッドに関しては、インスタンスを生成する必要がないので、{クラス名}.{メソッド名}({引数})という呼び出し方になります。

public static void main(String[] args) {
    LocalDateTime now = LocalDateTime.now();
    System.out.println(now.format(DateTimeFormatter.ISO_DATE_TIME));
}

変数

宣言と代入

int num1;
num1 = 5;
// 変数の宣言と値の代入(初期化)を同時に実行
int num2 = 8;
System.out.println(num1 + num2); // 13

{型名} {変数名}で変数を宣言できます。{変数名} = {値}で値を変数に代入することができます。
この2つの書き方を合わせて、変数の宣言と代入を一度に行うことができます。

インスタンスの生成

Object obj = new Object();

クラスを操作可能な状態にしたものをインスタンスといいます。クラスのインスタンスはnewというキーワードで生成することができます。このクラスが引数を持つコンストラクタを持っている場合は、newでの生成時にその引数に対応する値を渡します。

Integer number1 = new Integer(8);
Integer number2 = new Integer("14");

System.out.println(number1 + number2); // 22

変数のスコープ

public class Main {

    private String str1 = "メンバ変数です";

    public void mainMethod() {
        String str2 = "ローカル変数(mainメソッドの中だけ)です";

        if (true) {
            String str3 = "ローカル変数(ifの中だけ)です";
        }
        privateMethod();

        System.out.println(str1);
        System.out.println(str2);
        // System.out.println(str3); コンパイルエラー
        // System.out.println(str4); コンパイルエラー
    }

    private void privateMethod() {
        String str4 = "ローカル変数(privateMethodの中だけ)です";
        
        System.out.println(str1);
        // System.out.println(str2); コンパイルエラー
        // System.out.println(str3); コンパイルエラー
        System.out.println(str4);
    }
}

変数にはスコープという概念があります。簡単に言うとその変数が有効な範囲といえます。
基本的な考え方としては、Javaの変数のスコープはその変数が宣言された位置から外側の最も近い{}の範囲内となります。

当該の{}がクラス定義である変数をメンバ変数またはクラス変数と呼びます。これは、そのクラスのインスタンスが存在し続ける限り有効です。その他はローカル変数となりそのメソッドやもっと小さなブロックの処理が行われている間のみ有効となります。その外側で変数を使用しようとしてもコンパイルエラーとなります。

配列

int[] numArray = new int[3];
numArray[0] = 10;
// numArray[3] = 0; // ArrayIndexOutOfBoundsException

変数を定義するときの型名の後ろに[]を付与することでその型の配列として宣言することができます。
その中身はnew {型名}[{要素数}]で生成することができます。配列のそれぞれの要素へは{配列名}[{インデックス}]でアクセスできます。

様々な配列の扱い方を一気に紹介します。

// 値を初期化して生成
String[] fruits = { "りんご", "バナナ", "メロン" };
System.out.println(fruits[1]); // バナナ

// 多次元配列
String[][] twoDimensionalArray = new String[2][3];
twoDimensionalArray[0][0] = "Hello";

int[][] numbers = { { 12, 47, 51 }, { 43, 15, 27 } };
System.out.println(numbers[1][2]); // 27

定数

public class Main {

    private static final String FINAL_STR = "final";

    public static void main(final String[] args) {
        final Object finalObj = new Object();
    }
}

固有の意味を持つ文字列などを定数として保持したい場合には、クラス直下に{アクセス修飾子} static final {型名} {定数名} = {定数値}という形式で宣言します。この場合には、慣例的に定数名を大文字で指定します。変数にfinalを付与した場合は一度値が代入された後は再代入が不可能になります。

メソッド内で定義されるローカル変数や引数にfinalが付与される場合がありますが、これは「定数」として扱うために付与するというよりは、「再代入を防ぐ」目的になることが多く、そのような場合はfinalがついていても変数として扱い変数名も小文字のキャメルケースのままとします。

メンバ変数をstatic finalとする場合は、必要な場合を除いてアクセス修飾子はprivateとするようにしましょう。publicとする必要がある場合、まずはその定数をenumとして定義できないか検討してください。

finalは付与されている対象によってその効果が変わります。

  • クラスに付与されている場合、そのクラスを継承できなくなります。
  • メソッドに付与されている場合、そのメソッドはオーバーライドできなくなります。
  • 変数に付与されている場合、その変数は再代入できなくなります。

演算子と修飾子

算術演算子

int num = 1 + 2; // 3

+などの記号(演算子)を用いて四則演算などの計算ができます。

演算子役割
+加算 足し算
文字列に対して使用した場合は文字列の結合
-減算 引き算
*乗算 掛け算
/除算 割り算
%剰余 割り算の余り
例) 7 % 3 = 1
++インクリメント 1加算する
--デクリメント 1減算する

比較演算子

int a = 5 - 3;
int b = 1 + 1;

boolean bool = (a == b); // true

==などの記号を用いて2つの値の比較を行います。比較の結果が正しいかどうかをboolean(真偽値)で表現します。

演算子役割
==2つの値が等しいか比較する
1 == 1true 1 == 2false
!=2つの値が等しくないか比較する
1 != 2true 1 != 1false
<一方の値がもう一方の値より大きいか比較する
3 < 5true 3 < 3false 3 < 2false
<=一方の値がもう一方の値以上か比較する
3 <= 5true 3 <= 3true 3 <= 2false
>一方の値がもう一方の値より小さいか比較する
3 > 2true 3 > 3false 3 > 5false
>=一方の値がもう一方の値以下か比較する
3 >= 2true 3 >= 3true 3 >= 5false

論理演算子

boolean bool = true && true; // true

1つまたは2つの真偽値の組み合わせによって真偽値を返します。

演算子役割
&&AND AかつB
true && truetrue true && falsefalse false && falsefalse
||OR AまたはB
true || truetrue true || falsetrue false || falsefalse
!NOT Aではない
!truefalse !falsetrue
^XOR 排他的論理和 片方だけtrueならtrue
true ^ truefalse true ^ falsetrue false ^ falsefalse

アクセス修飾子

private String str;

クラス、コンストラクタ、メンバ変数、メソッドに対してアクセス修飾子を付与することで、それらの要素にアクセスできる範囲を制限することができます。

修飾子役割
publicすべてのクラスからアクセス可能
protected自クラスとそのサブクラスからのみアクセス可能
private自クラスからのみアクセス可能
修飾子なし自クラスと同じパッケージのクラスからのみアクセス可能
パッケージプライベートと呼ぶ

また、他のクラスに自クラスを参照させるためにpackage文を、自クラスで他のクラスを参照するためにimport文を記載する必要があります。

package sample; // このクラスが「sample」パッケージに属していることを宣言する

// クラス内で参照しているクラスを最初にimportする
import java.io.InputStream;
import java.io.OutputStream;

分岐

if

int age = 24;

if (40 <= age) {
    System.out.println("ベテラン");
} else if (30 <= age) {
    System.out.println("中堅");
} else {
    System.out.println("若手");
}

if ({条件式})の形式で書きます。else if()はelseとifの間にスペースを入れないとコンパイルエラーとなります。条件式にはbooleanの値を返却する式を指定する必要があります。

三項演算子

String position = 25 <= age ? "一人前" : "見習い";
System.out.println(position); // 見習い

条件によって返す値を変化させられる方法として、if文よりも簡素に記述できるのが三項演算子です。
{型名} {変数名} = {条件式} ? {真(true)の場合の返却値} : {偽(false)の場合の返却値}という構文になります。返却値と代入される変数の型は一致させる必要があります。
単純な条件分岐を省略して書く場合に使用してください。

switch-case

String fruit = "バナナ";

switch (fruit) {
    case "リンゴ":
        System.out.println("リンゴです");
        break;
    case "バナナ":
        System.out.println("バナナです");
        break;
    case "メロン":
        System.out.println("メロンです");
        break;
    default:
        System.out.println("フルーツです");
        break;
} // バナナです

switch ({比較元})で宣言し、case {比較対象}と定義します。比較元と比較対象は同じ型である必要があります。(厳密にいうと比較元と比較対象はequalsメソッドを使用して一致判定をしますので、同じ型でないと正しく判定ができません。)

例の中のbreakは、そこに到達した場合に以降の処理を行わずそのブロックを抜けるという意味を持ちます。switch文内ではcaseごとにbreakをしないと、次のcaseの内容の処理もしてしまいます。

Enumクラスを使用してswitch文を記述することもできます。

public enum Fruit {

    APPLE("リンゴ"), BANANA("バナナ"), MELON("メロン");

    private String name;

    private Fruit(String name) {
        this.name = name;
    }
}
Fruit enumFruit = Fruit.MELON;

switch (enumFruit) {
    case APPLE:
        System.out.println("リンゴです");
        break;
    case BANANA:
        System.out.println("バナナです");
        break;
    case MELON:
        System.out.println("メロンです");
        break;
    default:
        System.out.println("フルーツです");
        break;
} // メロンです

ループ

for

String[] fruits = { "いちご", "みかん", "レモン", "キウイ", "もも" };

for (int i = 0; i < fruits.length; i++) {
    System.out.println(fruits[i]);
} // いちごみかんレモンキウイもも

for ({初期値}; {継続条件}; {増分})という順番で記載します。
配列やコレクションに対しては拡張for文という構文が使えます。よりスッキリ直感的に書けます。

String[] fruits = { "いちご", "みかん", "レモン", "キウイ", "もも" };

for (String fruit : fruits) {
    System.out.println(fruit);
} // いちごみかんレモンキウイもも

while

String[] fruits = { "いちご", "みかん", "レモン", "キウイ", "もも" };

int i = 0;
while (i < fruits.length) {
    System.out.println(fruits[i]);
    i++;
} // いちごみかんレモンキウイもも

while({継続条件})でループを実行します。意図的に無限ループを発生させる場合はwhile(true)とします。
書き方の亜種としてdo-whileという構文もあります。(使用はお勧めしません。)

String[] fruits = { "いちご", "みかん", "レモン", "キウイ", "もも" };

int i = 0;
do {
    System.out.println(fruits[i]);
    i++;
} while (i < fruits.length); // いちごみかんレモンキウイもも

また、while文ではループを制御するbreakcontinueを併せて使用するケースが多いです。breakはループを抜けます。continueはその段階で次のループに進みます。

String[] fruits = { "いちご", "みかん", "レモン", "キウイ", "もも" };

int i = 0;
while (i < fruits.length) {
    if (i == 2) {
        i++;
        // 文字出力の前にcontinue⇒レモンの出力を飛ばす
        continue;
    }
    System.out.println(fruits[i]);
    i++; 
    if (i >= 4)
        // iが4になった段階でループを抜ける⇒ももが出力される前にループを終了する
        break;
} // いちごみかんキウイ

その他

例外処理

public static void main(final String[] args) throws Exception {

    FileInputStream fis = null;
    try {
        File file = new File("path/to/empty");
        fis = new FileInputStream(file);
    } catch (FileNotFoundException e) {
        throw new Exception("ファイルがありません!", e);
    } finally {
        if (fis != null) {
            fis.close();
        }
    }
}

プログラム実行中の想定外の状態に対する処理を例外処理と呼びます。Exceptionという例外発生を表現するクラスのインスタンスを生成して、それをやり取りすることで例外を処理します。

例外が発生する可能性のある処理をtryブロックで囲み、発生する例外を定義したcatchブロックを作成すると、一致する例外が発生した場合にcatchブロック内の処理が実行されます。例外発生の有無にかかわらずfinallyブロックの処理は必ず実行されます。

例外が発生したことを呼び出し元に伝える場合には、throw句を使用し、伝える例外インスタンスを指定します。また、例外をthrowする可能性のあるメソッドは、メソッド宣言時にthrows句を使用してthrowする可能性のある例外クラスを提示します。こうすることで、呼び出し元はその可能性を考慮して実装することができるようになります。

この構文は上記例のFileInputStreamのようなリソースをクローズする必要のあるクラスと併用されることが多いです。そのたびに上記例のようにfinally句でnullでないことを確認してからクローズするのは冗長な記述となります。
これを簡略化して書けるように、Javaではtry-with-resources構文が使用できます。

public static void main(final String[] args) throws Exception {

    try (FileInputStream fis = new FileInputStream(new File("path/to/empty"))) {
    } catch (FileNotFoundException e) {
        throw new Exception("ファイルがありません!", e);
    }
}

static

public class Main {

    private final static String STATIC_STR = "static";

    public static void main(final String[] args) throws Exception {
        System.out.println(STATIC_STR);
    }
}

static修飾子がついたメンバ変数やメソッドは、そのクラスをインスタンス化せずともアクセスして使用することができます。定数を宣言する場合や、引数の値によってのみ出力結果が決まるような関数型のメソッド(状態を持たない、意識しないメソッド)に付与することで、使いやすくなりメモリ効率も向上させることができます。

thisとsuper

public class Sample extends Object {

    private int age;

    public Sample(int age) {
        super();
        this.age = age;
    }
}

thisは自分のクラスのメンバ変数やコンストラクタを指すときに使用します。
superは自分のスーパークラスのメンバ変数やコンストラクタを指すときに使用します。

コメント

public class Main {

    /**
     * これはJavadocコメントです
     * @param args
     */
    public static void main(final String[] args) {

        // これはコメントです
        
        /*
         * これはコメントブロックです
         * 複数行コメントになります
         */
        
        System.out.println("Hello World");
    }
}

通常のコメントは//の後ろに記載します。/*から始まるのはコメントブロックとなり、複数行にわたってコメントとなります。/**から始まるのはJavadocコメントとなり、そのソースを説明するドキュメントコメントとなります。基本的にはクラス、コンストラクタ、メソッドに対してJavadocコメントを書きます。


かなり駆け足になってしまいましたが、Java言語の概要は覚えられましたでしょうか?
長くJava言語でプログラミングされている方でも、ふとした時に文法をド忘れしてしまうことはあると思います。そんなときにこの記事が役に立てば幸いです。

コメント

タイトルとURLをコピーしました