コンテンツにスキップ

9-1. 変数・データ型・制御フロー

  • Javaプログラムの基本構造(クラス・mainメソッド・コンパイル)を理解する
  • プリミティブ型と参照型の違いを学び、適切に使い分ける
  • 文字列操作と equals() による比較の重要性を理解する
  • if/switch/ループによる制御フローをJavaで書けるようになる
  • NullPointerException の原因と対策を知る

第4章ではプログラミングの概念を言語横断的に学んだ。この章では Java という言語の具体的な文法を習得する。Javaは静的型付け・オブジェクト指向を特徴とし、Spring Bootによる業務アプリケーション開発(第10章)への直接的な基礎となる。

HelloWorld.java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
JavaのファイルとクラスとJVMの関係
┌──────────────────────────────────┐
│ HelloWorld.java(ソースコード) │
│ ↓ javac でコンパイル │
│ HelloWorld.class(バイトコード) │
│ ↓ JVMが実行 │
│ 実行結果 │
└──────────────────────────────────┘
  • 1ファイルに1クラスpublic class のクラス名とファイル名は一致させる)
  • main メソッドがエントリーポイント
  • 文は ; で終わる
  • JavaScriptと違いコンパイルが必要(型チェックはコンパイル時に行われる)

Javaは 静的型付け言語 で、変数を宣言するときに型を明示する。

// 整数
byte b = 127; // 8bit (-128 〜 127)
short s = 32767; // 16bit
int i = 2_147_483_647; // 32bit ← 最もよく使う
long l = 9_223_372_036_854_775_807L; // 64bit(末尾にL)
// 小数
float f = 3.14f; // 32bit(末尾にf)
double d = 3.14159265; // 64bit ← 最もよく使う
// 文字・論理
char c = 'A'; // 16bit Unicode 1文字(シングルクォート)
boolean flag = true; // true / false
プリミティブ型のメモリイメージ
int x = 42;
┌──────┐
│ 42 │ ← スタックに値そのものが格納される
└──────┘

プリミティブ型以外はすべて参照型。オブジェクトへの参照(アドレス)を保持する。

String name = "Alice"; // 文字列(よく使う参照型)
int[] nums = {1, 2, 3}; // 配列
String name = "Alice";
name ───→ ┌────────┐
│ "Alice"│ ← ヒープ領域にオブジェクトが格納される
└────────┘

Java 10以降、ローカル変数に var が使えるようになった。

var message = "Hello"; // String と推論される
var count = 0; // int と推論される
var list = new ArrayList<String>(); // 型が明確なときに便利
// メソッドの引数・戻り値・フィールドには使えない
// public var name = "Alice"; // コンパイルエラー
// 暗黙の型変換(小さい型 → 大きい型は自動)
int i = 42;
long l = i; // OK
double d = i; // OK
// 明示的なキャスト(大きい型 → 小さい型は明示が必要)
double pi = 3.14159;
int n = (int) pi; // 3(小数点以下は切り捨て)
// String への変換
String s1 = String.valueOf(42); // "42"
String s2 = Integer.toString(42); // "42"
String s3 = 42 + ""; // "42"(Javaでは + が文字列連結になる)
// String から数値への変換
int parsed = Integer.parseInt("42"); // 42
double parsedD = Double.parseDouble("3.14"); // 3.14

JavaのStringはイミュータブル(変更不可)なオブジェクト。

String s = "Hello, World!";
s.length() // 13
s.charAt(0) // 'H'
s.substring(7, 12) // "World"
s.toLowerCase() // "hello, world!"
s.toUpperCase() // "HELLO, WORLD!"
s.trim() // 前後の空白を除去
s.contains("World") // true
s.startsWith("Hello") // true
s.replace("World", "Java") // "Hello, Java!"
s.split(", ") // ["Hello", "World!"](String[])
// 文字列の連結
String a = "Hello";
String b = "World";
String c = a + ", " + b + "!"; // "Hello, World!"
// 文字列フォーマット(テンプレートリテラルに相当)
String name = "Alice";
int score = 95;
String msg = String.format("こんにちは、%sさん!スコアは%d点です。", name, score);
// または Java 15以降
String msg2 = "こんにちは、%s さん!スコアは%d点です。".formatted(name, score);
// 大量の連結は StringBuilder を使う(String の + はループ内では非効率)
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100; i++) {
sb.append(i).append(", ");
}
String result = sb.toString();
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");
s1 == s2 // true(文字列リテラルはキャッシュされる場合がある)
s1 == s3 // false(new で作るとアドレスが異なる)
s1.equals(s3) // true(値の比較)
s1.equalsIgnoreCase("HELLO") // true(大文字小文字を無視)
// Javaで文字列比較は必ず equals() を使う
// == はアドレス比較になってしまう

Java最重要ルール:文字列は == ではなく equals() で比較する

int score = 75;
if (score >= 90) {
System.out.println("");
} else if (score >= 70) {
System.out.println(""); // ← これが出力される
} else if (score >= 60) {
System.out.println("");
} else {
System.out.println("不可");
}
// 従来の switch(Java 13以前)
String day = "MONDAY";
switch (day) {
case "SATURDAY":
case "SUNDAY":
System.out.println("休日");
break;
case "MONDAY":
System.out.println("週明け"); // ← これが出力される
break;
default:
System.out.println("平日");
}
// 新しい switch 式(Java 14以降)
String label = switch (day) {
case "SATURDAY", "SUNDAY" -> "休日";
case "MONDAY" -> "週明け";
default -> "平日";
};
// for ループ
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
// while ループ
int count = 0;
while (count < 3) {
System.out.println(count);
count++;
}
// 配列・コレクションの for-each(拡張for)
int[] nums = {10, 20, 30, 40, 50};
for (int n : nums) {
System.out.println(n);
}
// break と continue
for (int i = 0; i < 10; i++) {
if (i == 5) break; // ループを終了
if (i % 2 == 0) continue; // 偶数はスキップ
System.out.println(i); // 1, 3
}

Javaで最も多いエラーが NullPointerException(NPE)。null 参照のメソッドを呼び出したときに発生する。

import java.util.Objects;
String name = null;
name.length(); // NullPointerException!
// null チェック
if (name != null) {
System.out.println(name.length());
}
// Objects.requireNonNull:引数のnullチェックに
public void setName(String name) {
this.name = Objects.requireNonNull(name, "nameはnullにできません");
}
項目ポイント
変数宣言型を明示する(intdoubleString など)
プリミティブ型値を直接格納。intdoublebooleanchar など
参照型オブジェクトへの参照を保持。null になり得る
文字列比較== は不可。必ず .equals() を使う
NPE対策null チェック・Optional で防ぐ