cv.cm

コーディング · プログラミング言語

Java入門チュートリアル(初心者向け)

約11分で読めます

結論

Javaは静的型付けのオブジェクト指向言語で、バイトコードにコンパイルされ、どのOS上でもJava仮想マシン(JVM)で動作します。JDKをインストールし、クラスを Hello.java に保存して java Hello.java で実行します。クラスとオブジェクト、プリミティブ型と参照型、コレクションフレームワーク(List、Map、Set)、検査例外、そしてレコード、var、パターンマッチングといった新しい機能が中心的な内容です。

正規表現テストを開く

Javaとは何か、何に使われるか

Javaは1995年にSun Microsystemsが公開した言語で、現在はオープンなOpenJDKプロジェクトで開発され、Oracleが中心的な役割を担っています。「Write once, run anywhere(一度書けばどこでも動く)」が特徴で、コンパイラが生成したバイトコードをJVMがWindows、macOS、Linuxで実行します。大規模な業務システムのバックエンド(Spring Bootがよく使われます)、Androidアプリ(Kotlinと併用)、Apache KafkaやHadoopなどのビッグデータ基盤、多くのデスクトップ・組み込みシステムで使われています。新バージョンは6か月ごとにリリースされ、本番ではJava 21などの長期サポート(LTS)版を選ぶのが一般的です。

JDKのインストールと Hello, world の実行

JDK(Java Development Kit)をインストールします。Eclipse TemurinなどのOpenJDKビルドや、OracleのJDKが使えます。java -version で確認します。Javaのプログラムはすべてクラスの中に書き、実行は main から始まります。

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, world");
    }
}
java Hello.java        # run a single source file directly
# Hello, world
javac Hello.java       # or compile to Hello.class first
java Hello

ファイル名は public クラスの名前と一致させる必要があります(class Hello なら Hello.java)。

変数と基本の型

Javaには、値として直接格納される8つのプリミティブ型と、参照型(String や配列などのオブジェクト)があります。すべての変数には固定の型があり、メソッド内では var を使うと初期値からコンパイラが型を推論します。

型サイズ例
int32ビットint n = 42;
long64ビットlong big = 10_000_000_000L;
double64ビット浮動小数点数double pi = 3.14159;
booleantrue/falseboolean ok = true;
char16ビットのUTF-16単位char c = 'A';
byte, short, float8、16、32ビット使う機会は少なめ
String参照String s = "hi";
int count = 7;
double avg = count / 2;          // 3.0, integer division happens first
double avg2 = count / 2.0;       // 3.5
var name = "Ada";                // inferred as String
String msg = name + " has " + count + " items";
System.out.println(msg);         // Ada has 7 items
System.out.println(Integer.parseInt("12") + 1); // 13

これはコードの断片です。このような文は main などのメソッドの中に書いてください。

制御構文

int score = 72;
if (score >= 90) {
    System.out.println("A");
} else if (score >= 70) {
    System.out.println("B");     // B
} else {
    System.out.println("C");
}
for (int i = 0; i < 3; i++) {
    System.out.println(i);       // 0, 1, 2
}
String day = "SAT";
String kind = switch (day) {     // switch expression
    case "SAT", "SUN" -> "weekend";
    default -> "weekday";
};
System.out.println(kind);        // weekend

Javaには while、do/while のほか、配列やコレクションを順に処理する拡張 for (String s : list) ループもあります。

メソッド、クラス、レコード

クラスはフィールド(データ)とメソッド(振る舞い)をまとめます。static メソッドはクラス自体に属し、それ以外のメソッドは new で作ったオブジェクトに対して呼び出します。record は不変のデータクラスを簡潔に宣言する方法で、コンストラクタ、アクセサ、equals、hashCode、toString をコンパイラが生成します。

public class Shapes {
    static double square(double x) {
        return x * x;
    }
    static class Counter {
        private int value;
        void increment() { value++; }
        int get() { return value; }
    }
    record Point(int x, int y) {
        double distance() { return Math.sqrt(x * x + y * y); }
    }
    public static void main(String[] args) {
        System.out.println(square(4));        // 16.0
        Counter c = new Counter();
        c.increment();
        c.increment();
        System.out.println(c.get());          // 2
        Point p = new Point(3, 4);
        System.out.println(p + " " + p.distance()); // Point[x=3, y=4] 5.0
    }
}

クラスは親クラスを1つだけ継承(extends)でき、インターフェースは複数実装(implements)できます。フィールドは通常 private にして、メソッド経由でアクセスします。

コレクション:List、Map、Set

java.util のコレクションフレームワークは、サイズを変更できるデータ構造を提供します。コレクションはオブジェクトを保持するため、プリミティブ型は自動的にボクシングされます(int は Integer になります)。

import java.util.*;
public class Collections101 {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<>(List.of(3, 1, 2));
        nums.add(5);
        Collections.sort(nums);
        System.out.println(nums + " " + nums.get(0));  // [1, 2, 3, 5] 1
        Map<String, Integer> ages = new HashMap<>();
        ages.put("ann", 31);
        ages.put("bob", 25);
        System.out.println(ages.getOrDefault("zed", 0)); // 0
        Set<String> tags = new TreeSet<>(List.of("b", "a", "b"));
        System.out.println(tags);                        // [a, b]
        List<Integer> evensSquared = nums.stream()
            .filter(n -> n % 2 == 0)
            .map(n -> n * n)
            .toList();
        System.out.println(evensSquared);                // [4]
    }
}

最後の文はストリームとラムダ式を使っており、コレクションを変換する関数型のスタイルです。List.of は変更できないリストを作ります。変更したい場合は new ArrayList<>(...) で包みます。

特徴的な機能:静的型付け、インターフェース、パターンマッチング

インターフェースは多くのクラスが実装できる契約を定義するもので、Javaの設計の基礎です。現代のJavaにはパターンマッチングがあり、instanceof や switch で型の判定と変数の束縛を一度に行えます。シールドインターフェース(Java 17以降)は許可される実装をすべて列挙するため、switch がすべてのケースを網羅しているかをコンパイラが検査できます。

public class Areas {
    sealed interface Shape permits Circle, Rect {}
    record Circle(double r) implements Shape {}
    record Rect(double w, double h) implements Shape {}
    static double area(Shape s) {
        return switch (s) {
            case Circle c -> Math.PI * c.r() * c.r();
            case Rect r -> r.w() * r.h();
        };
    }
    public static void main(String[] args) {
        System.out.println(area(new Rect(2, 3)));  // 6.0
    }
}

このような switch のパターンマッチングは、Java 21 LTS以降で標準機能です。

例外処理

エラーは例外として扱われます。検査例外(IOException など)は捕捉するか throws で宣言する必要があります。非検査例外(NullPointerException のような RuntimeException のサブクラス)は不要です。try-with-resources は、ファイルや接続を自動的に閉じます。

import java.io.*;
import java.nio.file.*;
public class ReadFirst {
    static int parseAge(String text) {
        int age = Integer.parseInt(text);   // may throw NumberFormatException
        if (age < 0) throw new IllegalArgumentException("negative age");
        return age;
    }
    public static void main(String[] args) {
        try {
            System.out.println(parseAge("abc"));
        } catch (NumberFormatException e) {
            System.out.println("not a number");  // not a number
        }
        try (BufferedReader in = Files.newBufferedReader(Path.of("notes.txt"))) {
            System.out.println(in.readLine());
        } catch (IOException e) {
            System.out.println("cannot read: " + e.getMessage());
        }
    }
}

小さな完成プログラム:単語カウンター

import java.io.IOException;
import java.nio.file.*;
import java.util.*;
public class WordCount {
    public static void main(String[] args) throws IOException {
        if (args.length != 1) {
            System.err.println("usage: java WordCount.java FILE");
            System.exit(1);
        }
        String text = Files.readString(Path.of(args[0])).toLowerCase();
        Map<String, Integer> counts = new HashMap<>();
        for (String word : text.split("[^a-z']+")) {
            if (!word.isEmpty()) counts.merge(word, 1, Integer::sum);
        }
        counts.entrySet().stream()
            .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
            .limit(5)
            .forEach(e -> System.out.printf("%5d  %s%n", e.getValue(), e.getKey()));
    }
}

java WordCount.java notes.txt で実行します。出現回数の多い単語を上位5件、回数とともに表示します。

初心者がよくやる間違い

  • 整数の除算:5 / 2 は 2 です。2.5 を得るには、どちらかを double にします。
  • null に対してメソッドを呼び出して NullPointerException が発生する。null をチェックするか、値がないかもしれない場合は Optional を使います。
  • List.of で作ったリストを変更しようとして、UnsupportedOperationException が発生する。
  • 配列や List のインデックスが0から始まることを忘れ、最後の要素が length - 1 にあることを見落とす。

次のステップ

公式のJava開発者向けサイトdev.javaの学習パスに沿って学び、Java SE APIドキュメントをリファレンスとして手元に開いておきましょう。ビルドツール(MavenまたはGradle)、JUnitによる単体テストを学び、続いてWebサービス向けのSpring Bootなどのフレームワークに進みます。同じくJVMで動くKotlinも、次に学ぶ言語として自然な選択です。

よくある質問

Javaは習得が難しいですか?

Javaは型を宣言し、コードをクラスの中に書く必要があるため、Pythonより記述が冗長になります。ただし規則は一貫しており、コンパイラが早い段階でミスを説明してくれます。多くの大学が最初の言語として採用しています。

JDKとJVMの違いは何ですか?

JVMはコンパイル済みのバイトコードを実行します。JDKは開発キット一式で、JVMに加えてコンパイラ javac、標準ライブラリ、各種ツールが含まれます。開発者がインストールするのはJDKです。

どのバージョンのJavaを学ぶべきですか?

Java 21やそれ以降のLTSなど、現行の長期サポート版を学びましょう。古いコードも新しいJVMで動くため、最新の知識は既存プロジェクトにも役立ちます。

JavaとJavaScriptは同じものですか?

いいえ。名前は似ていますが、型システム、実行環境、用途の異なる別々の言語です。

Javaはまだ使われていますか?

はい。業務システムのバックエンド、Android、データ基盤で、今でも最も使われている言語の一つです。

コーディング講座の一覧