はじめに
Hello World
すべての Java プログラムは main() から開始されます。ファイル名は public クラス名と一致する必要があります(Main.java → Main.class)。javac がバイトコード(.class)にコンパイルし、java が JVM 上で実行します。System.out.println は stdout に出力し、printf はフォーマット指定子(%s、%d、%f、%n は改行)をサポートします。
// Main.java
public class Main {
public static void main(String[] args) {
System.out.println("Hello, World!");
System.out.printf("Name: %s, Age: %d%n", "Alice", 30);
}
}
// Compile: javac Main.java -> Main.class
// Run: java Main
// Package: java -cp . com.example.Main
// Every Java program needs:
// 1. A class (public class, file name must match)
// 2. A main method: public static void main(String[] args)変数とプリミティブ型
Java には8つのプリミティブ型(int、long、double、float、boolean、char、byte、short)と参照型(String、配列、オブジェクト)があります。 定数には 'final' を使用します。'var'(Java 10+)はコンパイル時に型を推論します — 型が明らかなローカル変数に使用します。数値のアンダースコア(100_000)は可読性を向上させます。
// Primitive types (8 total)
int age = 30; // 32-bit integer
long bigNum = 100_000L; // 64-bit integer
double price = 19.99; // 64-bit float (default for decimals)
float pi = 3.14f; // 32-bit float
boolean active = true; // true/false
char grade = 'A'; // 16-bit Unicode character
byte b = 127; // 8-bit signed
short s = 32767; // 16-bit signed
// Reference types
String name = "Alice"; // Object (not primitive)
int[] nums = {1, 2, 3}; // Array object
// Constants
final double PI = 3.14159; // can't be reassigned
// var (Java 10+, local type inference)
var count = 42; // inferred as int
var list = new ArrayList<String>(); // inferred as ArrayList<String>ラッパークラスとボクシング
ラッパークラス(Integer、Double、Boolean など)はプリミティブ型のオブジェクト版です。自動ボクシング/アンボクシングで自動変換されます。Integer は -128 から 127 までの値をキャッシュするため、小さい数では == が動作しますが大きい数では失敗します — 常に .equals() を使用してください。ラッパーはコレクション(プリミティブを保持できない)に必要です。
// Wrapper classes (Object versions of primitives)
Integer wrapped = Integer.valueOf(42); // explicit
Integer auto = 42; // autoboxing
int unboxed = auto; // unboxing
// Useful methods
int max = Integer.MAX_VALUE; // 2147483647
String bin = Integer.toBinaryString(42);
int parsed = Integer.parseInt("42");
String s = String.valueOf(42);
// Other wrappers: Double, Boolean, Character, Long, Float
Double d = 3.14;
Boolean b = Boolean.TRUE;
Character c = 'A';
// Be careful with == on wrappers
Integer a = 127, b2 = 127; // a == b2: true (cached)
Integer x = 128, y = 128; // x == y: false (not cached)
// Always use .equals() for Integer comparisonパッケージとインポート
パッケージはクラスを整理し、名前の衝突を防ぎます。慣習:逆ドメイン名(com.example.app)。特定のクラスをインポートするかワイルドカード(*)を使用します。静的インポートは定数やメソッド(Math.PI、Math.sqrt)を取り込みます。完全修飾名はインポートなしで動作しますが冗長です。java.lang パッケージは自動インポートされます。
// Package declaration (must be first line)
package com.example.app;
// Import specific class
import java.util.List;
import java.util.ArrayList;
// Import all classes in a package
import java.util.*;
// Static import (for static members)
import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
// Usage
double area = PI * 5 * 5;
double root = sqrt(16);
// Fully qualified name (no import needed)
java.time.LocalDate today = java.time.LocalDate.now();
// Package naming convention: reverse domain
// com.google.gson, org.apache.commons, io.netty.channel入力と出力
System.out(stdout)、System.err(stderr)、System.in(stdin)。Scanner はコンソール入力を読み取る最も簡単な方法です — トークンを解析します(nextInt、nextDouble、nextLine)。リソースを解放するために必ず Scanner を閉じてください。コマンドライン引数は args[] にあります(args[0] は C のようにプログラム名ではなく最初の引数です)。
import java.util.Scanner;
// Console output
System.out.println("Hello"); // with newline
System.out.print("No newline"); // without newline
System.out.printf("Pi: %.2f%n", 3.14159); // formatted
// Console input with Scanner
Scanner scanner = new Scanner(System.in);
System.out.print("Enter name: ");
String name = scanner.nextLine();
System.out.print("Enter age: ");
int age = scanner.nextInt();
System.out.printf("Hi %s, age %d%n", name, age);
scanner.close(); // always close
// Command-line arguments
// java Main arg1 arg2
// args[0] = "arg1", args[1] = "arg2"文字列とフォーマ ット
String メソッド
文字列は不変です — メソッドは新しい文字列を返します。内容比較には常に .equals() を使用してください(== は参照を比較します)。compareTo() は順序付けのために負/ゼロ/正を返します(ソートに便利)。split() は String[] を返します。可変文字列には StringBuilder を使用してください。
String s = "Hello, World";
// Length and access
int len = s.length(); // 12
char c = s.charAt(0); // 'H'
// Comparison
s.equals("Hello, World"); // true (content comparison)
s.equalsIgnoreCase("hello, world"); // true
s.compareTo("Apple"); // positive (s > "Apple")
"abc".compareTo("abd"); // negative
// Search
s.indexOf("World"); // 7 (-1 if not found)
s.lastIndexOf("l"); // 10
s.contains("World"); // true
s.startsWith("Hello"); // true
s.endsWith("World"); // true
// Extract
s.substring(7); // "World"
s.substring(0, 5); // "Hello"
// Transform
s.toUpperCase(); // "HELLO, WORLD"
s.toLowerCase(); // "hello, world"
s.replace("o", "0"); // "Hell0, W0rld"
s.trim(); // remove whitespace
s.split(", "); // ["Hello", "World"]StringBuilder と連結
+ による文字列連結は毎回新しい String を作成します(ループ内では非効率)。StringBuilder は可変で、文字列を段階的に構築するのに効率的です。StringBuffer はスレッドセーフ版です(ほとんど必要ありません)。String.join() はデリミタで結合します。Java 11+ は文字列の繰り返しに repeat() を追加しました。
// String concatenation (creates new String each time)
String s = "Hello" + ", " + "World";
String formatted = String.format("%s is %d", "Alice", 30);
// StringBuilder (mutable, efficient for many concatenations)
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(", ");
sb.append("World");
sb.insert(5, " there");
sb.delete(5, 11);
sb.reverse();
String result = sb.toString();
// StringBuffer (thread-safe, slower than StringBuilder)
StringBuffer sbf = new StringBuffer("thread-safe");
// Join strings
String joined = String.join(", ", "a", "b", "c"); // "a, b, c"
// Repeat (Java 11+)
String repeated = "ab".repeat(3); // "ababab"文字列フォーマット
printf/format は C スタイルのフォーマット指定子を使用します:%d(int)、%f(float)、%s(string)、%c(char)、%b(boolean)、%x(16進数)。幅(%5d)、左揃え(%-5d)、ゼロ埋め(%05d)、精度(%.2f)。%n はプラットフォームの改行です。テキストブロック(Java 15+)は三重引用符でエスケープなしの複数行文字列を可能にします。
// printf / format specifiers
System.out.printf("Int: %d%n", 42);
System.out.printf("Float: %.2f%n", 3.14159); // 3.14
System.out.printf("String: %s%n", "hello");
System.out.printf("Char: %c%n", 'A');
System.out.printf("Bool: %b%n", true);
System.out.printf("Hex: %x%n", 255); // ff
System.out.printf("Octal: %o%n", 8); // 10
// Width and padding
System.out.printf("[%5d]%n", 42); // [ 42]
System.out.printf("[%-5d]%n", 42); // [42 ]
System.out.printf("[%05d]%n", 42); // [00042]
System.out.printf("[%8.2f]%n", 3.14); // [ 3.14]
// String.format returns a String
String s = String.format("Name: %s, Age: %d", "Alice", 30);
// Text blocks (Java 15+)
String json = """
{
"name": "Alice",
"age": 30
}
""";正規表現
Java の正規表現は Pattern(コンパイル済み)と Matcher(入力に適用)を使用します。String メソッド(matches、split、replaceAll)は便利なショートカットです。Java 文字列リテラルではバックスラッシュを2倍にする必要があります(\d で \d)。グループは括弧でキャプチャされ、置換では $1、$2 で参照されます。繰り返し使用する場合はパターンを一度コンパイルしてください。
import java.util.regex.*;
// String methods
"hello123".matches("[a-z]+\d+"); // true
"a,b,c".split(","); // ["a", "b", "c"]
"hello".replaceAll("l", "L"); // "heLLo"
// Pattern and Matcher
Pattern p = Pattern.compile("\\d{4}-\\d{2}-\\d{2}");
Matcher m = p.matcher("Date: 2024-01-15");
if (m.find()) {
System.out.println(m.group()); // "2024-01-15"
}
// Find all matches
while (m.find()) {
System.out.println(m.group());
}
// Replace with regex
String result = "2024-01-15".replaceAll(
"(\\d{4})-(\\d{2})-(\\d{2})",
"$3/$2/$1"); // "15/01/2024"
// Common patterns
String email = "^[\\w.]+@[\\w.]+\\.\\w+$";
String phone = "^\\d{3}-\\d{4}$";数値と数学
Math クラスは静的数学関数を提供します。Math.random() は 0.0-1.0 を返します。より制御が必要な場合は java.util.Random(シード設定可能)や java.security.SecureRandom(暗号学的)を使用します。Integer/Double には静的ユーティリティメソッドがあります。浮動小数点精度に注意してください — 金融計算には BigDecimal を使用します。
// Math class
double sqrt = Math.sqrt(16); // 4.0
double pow = Math.pow(2, 10); // 1024.0
int abs = Math.abs(-5); // 5
int max = Math.max(3, 7); // 7
int min = Math.min(3, 7); // 3
double rounded = Math.round(3.7); // 4
double ceil = Math.ceil(3.1); // 4.0
double floor = Math.floor(3.9); // 3.0
double random = Math.random(); // 0.0 to 1.0
// Constants
double pi = Math.PI; // 3.14159...
double e = Math.E; // 2.71828...
// Integer/Long methods
int sum = Integer.sum(3, 4); // 7
int max2 = Integer.max(3, 7); // 7
// Rounding modes
double r = Math.round(3.5); // 4 (round half up)
double r2 = Math.floor(3.5 + 0.5); // alternative
// Random (java.util.Random)
import java.util.Random;
Random rand = new Random();
int n = rand.nextInt(100); // 0-99
double d = rand.nextDouble(); // 0.0-1.0
boolean b = rand.nextBoolean();制御フロー
If / Else
Java の if/else は C/C++ と同様に動作します。条件は boolean でなければなりません — JavaScript のような真/偽判定はありません(0 と空でない文字列は真ではありません)。三項演算子(cond ? a : b)は式であり文ではありません。単文本体でもブレースを使用してください(コードスタイルのベストプラクティス)。
int score = 85;
if (score >= 90) {
System.out.println("A");
} else if (score >= 80) {
System.out.println("B");
} else if (score >= 70) {
System.out.println("C");
} else {
System.out.println("F");
}
// Ternary operator
String grade = score >= 60 ? "Pass" : "Fail";
// Nested if
if (score >= 60) {
if (score >= 90) {
System.out.println("Excellent");
}
}
// Note: conditions must be boolean (no truthy/falsy)
// if (score) { } // Error: int is not booleanSwitch と式
従来の switch はフォールスルーします(break を使用)。Java 14+ の switch 式(->)はフォールスルーせず、値を返せます。複数の case ラベルにカンマを使用します(case 1, 2, 3)。'yield' は複雑なブロックから値を返します。switch 式は網羅的です — enum の場合は default またはすべての case が必要です。
// Traditional switch (fall-through)
int day = 3;
switch (day) {
case 1:
System.out.println("Mon");
break;
case 2:
case 3:
case 4:
System.out.println("Midweek");
break;
case 6:
case 7:
System.out.println("Weekend");
break;
default:
System.out.println("Invalid");
}
// Switch expression (Java 14+, no fall-through)
String type = switch (day) {
case 1, 2, 3, 4, 5 -> "Weekday";
case 6, 7 -> "Weekend";
default -> "Invalid";
};
// Switch with yield (for complex blocks)
int result = switch (day) {
case 1, 2, 3, 4, 5 -> {
int hours = 8;
yield hours * 5;
}
case 6, 7 -> 0;
default -> -1;
};ループ
Java には for、while、do-while ループがあります。拡張 for(for-each)は配列と任意の Iterable で動作します。break はループを終了し、continue は次の反復にスキップします。コレクションでは、インデックス付きループより for-each またはストリームを優先してください。do-while は少なくとも1回実行されます(稀に使用)。
// For loop
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
// Enhanced for (for-each)
int[] nums = {1, 2, 3, 4, 5};
for (int n : nums) {
System.out.println(n);
}
List<String> names = List.of("Alice", "Bob");
for (String name : names) {
System.out.println(name);
}
// While loop
int count = 0;
while (count < 3) {
System.out.println(count);
count++;
}
// Do-while (runs at least once)
int i = 0;
do {
System.out.println(i);
i++;
} while (i < 3);
// Break and continue
for (int j = 0; j < 10; j++) {
if (j == 5) break; // exit loop
if (j % 2 == 0) continue; // skip iteration
System.out.println(j);
}ラベル付き Break と Continue
ラベル(outer:)はネストされたループから外側のループを break/continue できます。これは稀にしか必要ありません — return でメソッドに抽出する方が通常はクリーンです。ラベルはループの前にコロンを付けて配置します。break label はラベル付きループを終了し、continue label はその次の反復にスキップします。
// Labels for breaking out of nested loops
outer:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i == 1 && j == 1) {
break outer; // exits both loops
}
System.out.println(i + "," + j);
}
}
// Labeled continue
outer:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (j == 1) {
continue outer; // skip to next i
}
System.out.println(i + "," + j);
}
}
// Alternative: extract to method and use return
void findPair(int[][] matrix, int target) {
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (matrix[i][j] == target) return; // exit method
}
}
}配列
配列は固定長です(動的には ArrayList を使用)。Arrays.sort() はインプレースでソートします。Arrays.toString() は読みやすい表現を提供します。Arrays.copyOf() は新しい長さでコピーを作成します。多次元配列では、各行が異なる長さを持てます(ジャグ配列)。配列のユーティリティメソッドには Arrays を使用してください。
// Declare and initialize
int[] nums = {1, 2, 3, 4, 5};
int[] empty = new int[5]; // [0, 0, 0, 0, 0]
String[] names = new String[3]; // [null, null, null]
// Access and modify
nums[0] = 10;
int first = nums[0]; // 10
int length = nums.length; // 5
// Multidimensional
int[][] matrix = {{1, 2}, {3, 4}};
int val = matrix[0][1]; // 2
// Arrays utility class
import java.util.Arrays;
int[] sorted = {3, 1, 2};
Arrays.sort(sorted); // [1, 2, 3]
int[] copy = Arrays.copyOf(nums, 3);
String str = Arrays.toString(nums); // "[10, 2, 3, 4, 5]"
boolean eq = Arrays.equals(nums, copy);
// Fill
int[] filled = new int[5];
Arrays.fill(filled, 42); // [42, 42, 42, 42, 42]
// Binary search (sorted array only)
int idx = Arrays.binarySearch(sorted, 2); // index of 2メソッドと関数
メソッドの定義
Java メソッドは常にクラス内にあります。'static' はメソッドがクラスに属することを意味します(インスタンスなしで呼び出し)。戻り型(int、String、void)は名前の前に宣言されます。パラメータは型付きです。Java にはデフォルトパラメータ値はありません — 代わりにメソッドオーバーロードを使用します。
public class Calculator {
// Method with return type
public static int add(int a, int b) {
return a + b;
}
// Void method (no return)
public static void printResult(int result) {
System.out.println("Result: " + result);
}
// Method with default (no overloading needed)
public static String greet(String name, String greeting) {
return greeting + ", " + name + "!";
}
public static void main(String[] args) {
int sum = add(3, 4);
printResult(sum);
String msg = greet("Alice", "Hello");
System.out.println(msg);
}
}メソッドのオーバーロード
メソッドオーバーロードは同じ名前で異なるパラメータリスト(型、数、順序)の複数メソッドを許可します。Java は引数の型に基づいてコンパイル時にオーバーロードを解決します。オーバーロードはコンストラクタとユーティリティメソッドで一般的です。オーバーライド(継承とランタイムディスパッチを伴う)とは異なります。
public class MathUtils {
// Overloaded methods (same name, different params)
public static int add(int a, int b) {
return a + b;
}
public static double add(double a, double b) {
return a + b;
}
public static int add(int a, int b, int c) {
return a + b + c;
}
public static String add(String a, String b) {
return a + b;
}
}
// Java picks the most specific match
MathUtils.add(1, 2); // int version -> 3
MathUtils.add(1.5, 2.5); // double version -> 4.0
MathUtils.add(1, 2, 3); // 3-param version -> 6
MathUtils.add("Hello", "!"); // String version -> "Hello!"可変長引数と値渡し
可変長引数(Type... name)は可変引数を許可し、配列として受け取ります。Java は常に値渡しです:プリミティブはコピーされ、オブジェクト参照はコピーされます(しかし同じオブジェクトを指します)。したがって、メソッド内でパラメータを変更しても呼び出し元の変数には影響しませんが、指す先のオブジェクトを変更すると影響します。
// Varargs: variable number of arguments
public static int sum(int... nums) {
int total = 0;
for (int n : nums) {
total += n;
}
return total;
}
sum(1, 2, 3); // 6
sum(1, 2, 3, 4, 5); // 15
sum(); // 0 (empty array)
int[] arr = {1, 2, 3};
sum(arr); // 6 (pass array to varargs)
// Java is ALWAYS pass-by-value
public static void modify(int x) {
x = 100; // doesn't affect the caller's variable
}
int n = 5;
modify(n);
System.out.println(n); // still 5
// For objects, the reference is passed by value
public static void addItem(List<String> list) {
list.add("new"); // modifies the same list object
}再帰
再帰はメソッドが自分自身を呼び出すことです。停止するためのベースケースを必ず持ってください。Java は末尾再帰を最適化しないため(一部の言語とは異なります)、深い再帰は StackOverflowError を引き起こす可能性があります。パフォーマンスが重要な、または深い再帰には反復に変換してください。メモ化(結果のキャッシュ)はフィボナッチのような再帰ソリューションを高速化できます。
// Factorial
public static int factorial(int n) {
if (n <= 1) return 1; // base case
return n * factorial(n - 1); // recursive case
}
// factorial(5) = 5 * 4 * 3 * 2 * 1 = 120
// Fibonacci
public static int fib(int n) {
if (n < 2) return n;
return fib(n - 1) + fib(n - 2);
}
// Tail recursion (Java doesn't optimize this)
public static int factorialTail(int n, int acc) {
if (n <= 1) return acc;
return factorialTail(n - 1, n * acc);
}
// Call: factorialTail(5, 1)
// Be careful: deep recursion causes StackOverflowError
// For deep recursion, use iteration or a loop insteadLambda 式
Lambda(Java 8+)は匿名関数です。型は関数型インターフェース(単一の抽象メソッド)です。一般的なもの:Function<T,R>(入力→出力)、Predicate<T>(boolean テスト)、Consumer<T>(消費、戻り値なし)、Supplier<T>(生成、入力なし)。メソッド参照(String::length)は単一メソッドを呼び出す lambda の短縮形です。
import java.util.function.*;
// Lambda syntax: (params) -> expression
Function<Integer, Integer> square = x -> x * x;
Function<String, Integer> length = s -> s.length();
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
// With type annotations
BinaryOperator<Integer> multiply = (Integer a, Integer b) -> a * b;
// Multi-line lambda
Function<String, String> process = s -> {
String upper = s.toUpperCase();
return upper.substring(0, 3);
};
// Predicate (boolean test)
Predicate<Integer> isEven = n -> n % 2 == 0;
Predicate<String> isEmpty = String::isEmpty; // method reference
// Consumer (no return)
Consumer<String> printer = s -> System.out.println(s);
Consumer<String> printer2 = System.out::println; // method reference
// Supplier (no input, produces value)
Supplier<Double> random = () -> Math.random();
// Usage
int result = square.apply(5); // 25
boolean even = isEven.test(4); // true
printer.accept("Hello"); // prints "Hello"クラスと OOP
クラスとコンストラクタ
クラスはオブジェクトのテンプレートです。フィールドが状態を保持し、メソッドが振る舞いを定義します。コンストラクタは新しいオブジェクトを初期化します('this' でフィールドとパラメータを区別)。@Override はメソッドがスーパークラスのメソッドをオーバーライドすることを示します(toString は Object から)。カプセル化:private フィールド、public getter/setter。
public class Person {
// Fields (instance variables)
private String name;
private int age;
// Constructor
public Person(String name, int age) {
this.name = name; // 'this' refers to the current instance
this.age = age;
}
// Methods
public String getName() { return name; }
public int getAge() { return age; }
public void setAge(int age) {
if (age >= 0) this.age = age;
}
public String greet() {
return "Hi, I'm " + name;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
// Usage
Person p = new Person("Alice", 30);
System.out.println(p.getName()); // "Alice"
System.out.println(p); // uses toString()アクセス修飾子と static
アクセス修飾子:public(どこでも)、private(クラスのみ)、protected(クラス + サブクラス + パッケージ)、default/package-private(同じパッケージ)。静的メンバーはインスタンスではなくクラスに属します — すべてのオブジェクトで共有されます。静的初期化子はクラスロード時に1回実行されます。定数(static final)、ユーティリティメソッド、カウンタに static を使用します。
public class BankAccount {
// Access modifiers:
public String owner; // accessible everywhere
private double balance; // class only
protected String type; // class + subclasses + same package
String id; // package-private (default)
// Static field (shared by all instances)
private static int accountCount = 0;
// Static constant
public static final double MIN_BALANCE = 100.0;
// Static method (call without instance)
public static int getAccountCount() {
return accountCount;
}
// Static initializer (runs once when class loads)
static {
System.out.println("BankAccount class loaded");
}
public BankAccount(String owner) {
this.owner = owner;
this.balance = MIN_BALANCE;
accountCount++; // increment shared counter
}
}
int count = BankAccount.getAccountCount(); // static method call継承と super
Java はクラス継承に 'extends' を使用します(単一継承のみ)。super() は親コンストラクタを呼び出します(最初の行でなければなりません)。@Override はメソッドオーバーライドを示します(ランタイムポリモーフィズム)。Dog IS-A Animal。'is-a' 関係に継承を使用し、コード再利用には合成(has-a)を使用します。Java 17+ は継承を制限する sealed クラスをサポートします。
// Parent class
class Animal {
protected String name;
public Animal(String name) {
this.name = name;
System.out.println("Animal constructor");
}
public void eat() {
System.out.println(name + " is eating");
}
}
// Child class (extends)
class Dog extends Animal {
private String breed;
public Dog(String name, String breed) {
super(name); // must be first line — call parent constructor
this.breed = breed;
}
// Override parent method
@Override
public void eat() {
super.eat(); // call parent's eat()
System.out.println(name + " the " + breed + " eats dog food");
}
public void bark() {
System.out.println("Woof!");
}
}
Dog dog = new Dog("Rex", "Labrador");
dog.eat(); // calls Dog's eat()
dog.bark(); // Dog-specific method抽象クラスとインターフェース
抽象クラスはインスタンス化できず、抽象(本体なし)と具象メソッドの両方を持てます。インターフェースは契約を定義します — すべてのメソッドはデフォルトで public abstract です。Java 8+ はインターフェースでデフォルトメソッド(本体付き)と静的メソッドを許可します。クラスは1つの抽象クラスを拡張できますが、複数のインターフェースを実装できます。共有コードには抽象クラスを、契約にはインターフェースを使用します。
// Abstract class (can't be instantiated)
abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// Abstract method (must be implemented by subclasses)
public abstract double area();
// Concrete method (inherited)
public String describe() {
return color + " " + this.getClass().getSimpleName();
}
}
// Interface (pure contract, Java 8+ can have default methods)
interface Drawable {
void draw(); // abstract by default
// Default method (Java 8+)
default void drawTwice() {
draw();
draw();
}
// Static method in interface
static Drawable empty() {
return () -> System.out.println("nothing");
}
}
// A class can extend one class and implement multiple interfaces
class Circle extends Shape implements Drawable {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
@Override
public void draw() {
System.out.println("Drawing " + describe());
}
}ポリモーフィズムとキャスト
ポリモーフィズム:親参照は子オブジェクトを保持できます。メソッド呼び出しは実際のオブジェクトの実装にディスパッチされます(ランタイムポリモーフィズム)。ClassCastException を回避するため、ダウンキャストの前に instanceof を使用します。Java 16+ のパターンマッチング(instanceof Circle c)はチェックとキャストを組み合わせます。コレクションでの正しい動作のために equals() と hashCode() を一緒にオーバーライドしてください。
// Polymorphism: one interface, many forms
Shape s1 = new Circle("red", 5);
Shape s2 = new Square("blue", 3);
// Calls the overridden method (runtime dispatch)
System.out.println(s1.area()); // Circle's area
System.out.println(s2.area()); // Square's area
// instanceof check
if (s1 instanceof Circle) {
Circle c = (Circle) s1; // downcast
System.out.println("Radius: " + c.radius);
}
// Pattern matching (Java 16+)
if (s1 instanceof Circle c) {
System.out.println("Radius: " + c.radius); // c is already cast
}
// Upcasting (automatic)
Circle circle = new Circle("green", 2);
Shape shape = circle; // upcast (no explicit cast needed)
// Object class methods (all classes inherit from Object)
circle.equals(circle); // reference equality by default
circle.hashCode(); // hash code
circle.getClass(); // Class<Circle>
circle.toString(); // string representationレコードと Enum
レコード(Java 16+)は不変データクラスです — コンパイラがコンストラクタ、getter、equals、hashCode、toString を生成します。DTO と値オブジェクトに使用します。Enum は型安全な定数で、フィールド、メソッド、コンストラクタを持てます。Enum は Comparable を実装し、values() と valueOf() メソッドを持ちます。どちらもモダン Java に不可欠です。
// Record (Java 16+): concise data class
public record Point(int x, int y) {}
// Equivalent to a class with:
// - final fields x, y
// - constructor
// - getters x(), y()
// - equals, hashCode, toString
Point p = new Point(3, 4);
System.out.println(p.x()); // 3
System.out.println(p.y()); // 4
System.out.println(p); // Point[x=3, y=4]
// Compact constructor (validation)
public record Age(int value) {
public Age {
if (value < 0 || value > 150) {
throw new IllegalArgumentException("Invalid age");
}
}
}
// Enum (named constants)
public enum Direction {
UP, DOWN, LEFT, RIGHT;
public Direction opposite() {
return switch (this) {
case UP -> DOWN;
case DOWN -> UP;
case LEFT -> RIGHT;
case RIGHT -> LEFT;
};
}
}
Direction d = Direction.UP;
Direction opp = d.opposite(); // DOWNコレクションとジェネリクス
List(ArrayList と LinkedList)
ArrayList は配列をベースにします(get/set が高速、中間の挿入/削除が遅い)。LinkedList は双方向リンクリストをベースにします(両端の挿入/削除が高速、ランダムアクセスが遅い)。List.of() は不変リストを作成します。ほとんどのケースでは ArrayList を使用し、頻繁な終端操作にのみ LinkedList を使用します。どちらも List インターフェースを実装します。
import java.util.*;
// ArrayList (fast random access, slow insert/delete in middle)
List<String> list = new ArrayList<>();
list.add("Alice");
list.add("Bob");
list.add(0, "Carol"); // insert at index
list.set(1, "Dave"); // replace at index
String name = list.get(0); // "Carol"
list.remove(0); // remove by index
list.remove("Dave"); // remove by value
int size = list.size(); // 1
boolean has = list.contains("Bob");
// LinkedList (fast insert/delete at ends)
LinkedList<Integer> linked = new LinkedList<>();
linked.addFirst(1);
linked.addLast(2);
linked.removeFirst();
linked.peek(); // see first element
// Immutable list (Java 9+)
List<String> immutable = List.of("a", "b", "c");
// immutable.add("d"); // UnsupportedOperationException
// Iterate
for (String s : list) {
System.out.println(s);
}
list.forEach(System.out::println); // method referenceSet(HashSet と TreeSet)
Set は一意の要素を格納します。HashSet が最速ですが順序なしです。TreeSet は要素をソートします(自然順序または Comparator)。LinkedHashSet は挿入順序を維持します。セット操作:addAll(和)、retainAll(積)、removeAll(差)。HashSet でカスタムオブジェクトを使用する場合、equals() と hashCode() をオーバーライドしてください。
import java.util.*;
// HashSet (fast, unordered)
Set<String> set = new HashSet<>();
set.add("apple");
set.add("banana");
set.add("apple"); // duplicate ignored
System.out.println(set.size()); // 2
System.out.println(set.contains("apple")); // true
set.remove("banana");
// TreeSet (sorted, slower)
Set<Integer> sorted = new TreeSet<>();
sorted.add(3);
sorted.add(1);
sorted.add(2);
System.out.println(sorted); // [1, 2, 3]
// LinkedHashSet (maintains insertion order)
Set<String> ordered = new LinkedHashSet<>();
ordered.add("c");
ordered.add("a");
ordered.add("b");
System.out.println(ordered); // [c, a, b]
// Set operations
Set<Integer> a = new HashSet<>(Set.of(1, 2, 3));
Set<Integer> b = new HashSet<>(Set.of(2, 3, 4));
a.addAll(b); // union: [1, 2, 3, 4]
a.retainAll(b); // intersection: [2, 3]
a.removeAll(b); // difference: [1]
// Immutable set
Set<String> immutable = Set.of("x", "y", "z");Map(HashMap と TreeMap)
Map はキーと値のペアを格納します。HashMap が最速(順序なし)。TreeMap はキーでソート。LinkedHashMap は挿入順序を維持。getOrDefault は null チェックを回避します。compute/merge は値の更新に強力です。カスタムキーの場合、equals() と hashCode() をオーバーライドしてください。Map.of() は不変マップを作成します(Java 9+)。
import java.util.*;
// HashMap (fast, unordered)
Map<String, Integer> ages = new HashMap<>();
ages.put("Alice", 30);
ages.put("Bob", 25);
ages.put("Alice", 31); // overwrite
// Access
int age = ages.get("Alice"); // 31
int defaultAge = ages.getOrDefault("Eve", 0); // 0
// Check
boolean has = ages.containsKey("Alice");
boolean hasVal = ages.containsValue(25);
// Remove
ages.remove("Bob");
// Iterate
for (Map.Entry<String, Integer> entry : ages.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
ages.forEach((key, val) -> System.out.println(key + "=" + val));
// Compute (Java 8+)
ages.compute("Alice", (k, v) -> v + 1); // increment
ages.putIfAbsent("Carol", 28);
ages.merge("Alice", 1, Integer::sum); // add 1
// TreeMap (sorted by keys)
Map<String, Integer> sorted = new TreeMap<>();
// LinkedHashMap (maintains insertion order)
Map<String, Integer> ordered = new LinkedHashMap<>();Queue と Deque
Queue は FIFO(先入れ先出し)です。Deque は両端(両端から追加/削除可能)。PriorityQueue は自然順序または Comparator で要素を順序付けします(デフォルトは最小ヒープ)。スタックにはレガシーの Stack クラスではなく ArrayDeque(push/pop)を使用します。Queue/Deque 操作には LinkedList より ArrayDeque が高速です。
import java.util.*;
// Queue (FIFO)
Queue<String> queue = new LinkedList<>();
queue.add("first"); // throws if full (capacity-restricted)
queue.offer("second"); // returns false if full
String head = queue.peek(); // see head (null if empty)
String removed = queue.poll(); // remove and return head
// Deque (double-ended)
Deque<Integer> deque = new ArrayDeque<>();
deque.addFirst(1);
deque.addLast(2);
deque.peekFirst(); // 1
deque.peekLast(); // 2
deque.pollFirst(); // 1
deque.pollLast(); // 2
// PriorityQueue (min-heap by default)
PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.add(3);
pq.add(1);
pq.add(2);
System.out.println(pq.poll()); // 1 (smallest first)
// Max-heap (reverse order)
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
maxHeap.add(1);
maxHeap.add(3);
System.out.println(maxHeap.poll()); // 3 (largest first)
// Stack (legacy, prefer Deque)
Deque<Integer> stack = new ArrayDeque<>();
stack.push(1); // add to front
stack.push(2);
stack.pop(); // 2 (remove from front)ジェネリクス
ジェネリクスは型安全なコレクションとクラスを可能にします。<T> は型パラメータです。境界付き型(<T extends Comparable<T>>)は特定の振る舞いを持つ型に制限します。ワイルドカード:?(任意)、? extends T(共変、読み取り専用)、? super T(反変、書き込み専用)。ジェネリクスは型消去を使用します — 型はコンパイル時にチェックされ、実行時に消去されます。
// Generic class
public class Box<T> {
private T value;
public void set(T value) { this.value = value; }
public T get() { return value; }
}
Box<String> stringBox = new Box<>();
stringBox.set("hello");
String s = stringBox.get();
Box<Integer> intBox = new Box<>();
intBox.set(42);
// Generic method
public static <T> T firstOf(List<T> list) {
return list.get(0);
}
String first = firstOf(List.of("a", "b"));
// Bounded type parameter
public static <T extends Comparable<T>> T max(List<T> list) {
T result = list.get(0);
for (T item : list) {
if (item.compareTo(result) > 0) {
result = item;
}
}
return result;
}
// Wildcards
void process(List<?> list) { } // any type
void processNums(List<? extends Number> list) { } // Number or subclass
void addNums(List<? super Integer> list) { } // Integer or superclassイテレータと Comparable
Iterator は反復中の安全な削除を許可します(it.remove())。ListIterator は双方向トラバーサルと set/add を追加します。Comparable は自然順序を定義します(compareTo)。Comparator はカスタム順序を定義します(comparing、comparingInt、reversed、thenComparing)。流暢なソートには Comparator.comparing() を使用します。Collections.sort() は自然順序を使用します。
import java.util.*;
// Iterator
List<String> list = List.of("a", "b", "c");
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
// it.remove(); // safe removal during iteration
}
// ListIterator (bidirectional)
ListIterator<String> lit = list.listIterator();
while (lit.hasNext()) {
lit.set(lit.next().toUpperCase()); // replace
}
// Comparable (natural ordering)
public class Person implements Comparable<Person> {
String name;
int age;
@Override
public int compareTo(Person other) {
return Integer.compare(this.age, other.age);
}
}
// Comparator (custom ordering)
Comparator<Person> byName = Comparator.comparing(p -> p.name);
Comparator<Person> byAgeDesc = Comparator.comparingInt((Person p) -> p.age).reversed();
List<Person> people = new ArrayList<>();
people.sort(byName);
people.sort(byAgeDesc);
Collections.sort(people); // uses Comparableストリームと関数型
ストリームの基礎
ストリーム(Java 8+)は宣言的データ処理を提供します。.stream()(コレクション)または Stream.of() で作成。中間操作(filter、map、sorted)は遅延です — 終端操作(collect、reduce、count、forEach)が呼ばれた時にのみ実行されます。toList()(Java 16+)は collect(Collectors.toList()) の簡潔な代替です。
import java.util.*;
import java.util.stream.*;
List<Integer> nums = List.of(1, 2, 3, 4, 5, 6);
// Filter and collect
List<Integer> evens = nums.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList()); // [2, 4, 6]
// Map (transform)
List<String> doubled = nums.stream()
.map(n -> "num" + n)
.collect(Collectors.toList());
// Reduce
int sum = nums.stream().reduce(0, Integer::sum); // 21
int product = nums.stream().reduce(1, (a, b) -> a * b);
// Count
long count = nums.stream().filter(n -> n > 3).count(); // 3
// Find
Optional<Integer> first = nums.stream().filter(n -> n > 3).findFirst();
boolean anyMatch = nums.stream().anyMatch(n -> n > 5);
boolean allMatch = nums.stream().allMatch(n -> n > 0);
// ForEach
nums.stream().forEach(System.out::println);
// toList() shortcut (Java 16+)
List<Integer> result = nums.stream().filter(n -> n > 3).toList();ストリーム操作
sorted() は要素を順序付けします(自然順序または Comparator)。distinct() は重複を削除。limit(n)/skip(n) はページネーション。flatMap はネストされたストリームを平坦化します — 1対多変換に不可欠。peek() はデバッグ用(副作用)。groupingBy は分類子で要素をグループ化するマップを作成します。ストリームは遅延です — 操作が効率的にチェーンされます。
List<String> names = List.of("Alice", "Bob", "Charlie", "David");
// Sorted
List<String> sorted = names.stream()
.sorted()
.toList();
// Sorted by length
List<String> byLength = names.stream()
.sorted(Comparator.comparing(String::length))
.toList();
// Distinct
List<Integer> distinct = List.of(1, 2, 2, 3, 3, 3).stream()
.distinct()
.toList(); // [1, 2, 3]
// Limit and Skip
List<Integer> limited = nums.stream()
.skip(2) // skip first 2
.limit(3) // take next 3
.toList();
// FlatMap (flatten nested structures)
List<List<Integer>> nested = List.of(List.of(1, 2), List.of(3, 4));
List<Integer> flat = nested.stream()
.flatMap(List::stream)
.toList(); // [1, 2, 3, 4]
// Peek (debug, side-effect)
nums.stream()
.peek(n -> System.out.println("before: " + n))
.filter(n -> n > 2)
.peek(n -> System.out.println("after: " + n))
.toList();
// Grouping
Map<Integer, List<String>> byLength = names.stream()
.collect(Collectors.groupingBy(String::length));コレクタとリダクション
コレクタは豊富なリダクション操作を提供します:joining(文字列連結)、groupingBy(キーでグループ化)、partitioningBy(boolean で分割)、toMap(マップ作成)、summarizingInt(統計:count、sum、min、max、average)。コレクタは合成できます(ダウンストリームコレクタ付きの groupingBy)。これらは冗長なループを宣言的なワンライナーに置き換えます。
import java.util.stream.*;
List<Person> people = List.of(
new Person("Alice", 30),
new Person("Bob", 25),
new Person("Charlie", 35)
);
// Join strings
String joined = people.stream()
.map(Person::getName)
.collect(Collectors.joining(", ")); // "Alice, Bob, Charlie"
// Group by
Map<Integer, List<Person>> byAge = people.stream()
.collect(Collectors.groupingBy(Person::getAge));
// Partition (boolean)
Map<Boolean, List<Person>> partition = people.stream()
.collect(Collectors.partitioningBy(p -> p.getAge() > 28));
// Count by group
Map<Integer, Long> countByAge = people.stream()
.collect(Collectors.groupingBy(Person::getAge, Collectors.counting()));
// Summarizing
IntSummaryStatistics stats = people.stream()
.collect(Collectors.summarizingInt(Person::getAge));
System.out.println(stats.getAverage()); // 30.0
System.out.println(stats.getMax()); // 35
// To map
Map<String, Integer> nameToAge = people.stream()
.collect(Collectors.toMap(Person::getName, Person::getAge));
// Reducing
int totalAge = people.stream()
.collect(Collectors.reducing(0, Person::getAge, Integer::sum));Optional
Optional<T> は値を含むかもしれないし含まないかもしれないコンテナです。不在の明示的な処理を強制します — もう NullPointerException はありません。非 null 値には of() を、null の可能性がある場合は ofNullable() を使用します。map/flatMap/filter でチェーン。isPresent() なしで get() を使用しないでください — orElse/orElseThrow を優先。Optional はフィールドではなく戻り値型用に設計されています。
import java.util.Optional;
// Creating Optional
Optional<String> present = Optional.of("hello");
Optional<String> empty = Optional.empty();
Optional<String> nullable = Optional.ofNullable(null); // empty if null
// Checking
present.isPresent(); // true
empty.isEmpty(); // true (Java 11+)
// Getting values
String val = present.get(); // throws if empty (avoid!)
String safe = present.orElse("default");
String computed = present.orElseGet(() -> computeDefault());
String orThrow = present.orElseThrow(() -> new RuntimeException("missing"));
// Transform (map/flatMap)
Optional<Integer> length = present.map(String::length); // Optional[5]
Optional<String> upper = present.map(s -> s.toUpperCase());
// Filter
Optional<String> filtered = present.filter(s -> s.length() > 3);
// ifPresent
present.ifPresent(s -> System.out.println(s));
present.ifPresentOrElse(
s -> System.out.println("Got: " + s),
() -> System.out.println("Empty")
);
// Chaining (avoid null checks)
String result = getUser(1)
.map(User::getProfile)
.map(Profile::getEmail)
.orElse("no email");関数型インターフェース
関数型インターフェースは正確に1つの抽象メソッドを持ちます(複数のデフォルトメソッドを持てます)。@FunctionalInterface は任意ですが意図を文書化します。Java は java.util.function に多くを提供します:Function、Predicate、Consumer、Supplier、plus Bi- およびプリミティブバリアント。可能な場合はカスタムインターフェースの作成の代わりにこれらを使用します。これらは lambda 式とメソッド参照を可能にします。
import java.util.function.*;
// Built-in functional interfaces
Function<String, Integer> strToInt = Integer::parseInt;
BiFunction<String, String, String> concat = String::concat;
Predicate<String> isEmpty = String::isEmpty;
BiPredicate<String, String> contains = String::contains;
Consumer<String> printer = System.out::println;
BiConsumer<String, Integer> printPair = (s, i) -> System.out.println(s + ":" + i);
Supplier<List<String>> listFactory = ArrayList::new;
// Primitive specializations
IntFunction<String> intToStr = String::valueOf;
ToIntFunction<String> length = String::length;
IntPredicate isPositive = n -> n > 0;
IntConsumer intPrinter = System.out::println;
IntSupplier randomInt = () -> (int)(Math.random() * 100);
// Binary operators
BinaryOperator<Integer> max = Integer::max;
IntBinaryOperator sum = Integer::sum;
// Unary operators
UnaryOperator<String> trim = String::trim;
IntUnaryOperator negate = n -> -n;
// Custom functional interface
@FunctionalInterface
interface StringProcessor {
String process(String input);
// Can have default methods
default StringProcessor andThen(StringProcessor after) {
return input -> after.process(process(input));
}
}例外と I/O
Try / Catch / Finally
try/catch/finally は例外を処理します。finally は常に実行されます(クリーンアップに使用)。マルチキャッチ(catch A | B)は複数の例外を一緒に処理します。try-with-resources は AutoCloseable(ファイル、接続、ストリーム)を自動クローズします — 手動の finally クリーアップより優先されます。リソースは宣言の逆順でクローズされます。
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("Math error: " + e.getMessage());
} catch (Exception e) {
System.out.println("General error: " + e);
} finally {
// Always runs (even if return/throw in try/catch)
System.out.println("Cleanup");
}
// Multi-catch (Java 7+)
try {
riskyOperation();
} catch (IOException | SQLException e) {
// Handle both exceptions the same way
log.error(e);
}
// Try-with-resources (auto-close, Java 7+)
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"));
PrintWriter pw = new PrintWriter("output.txt")) {
String line = br.readLine();
pw.println(line);
} catch (IOException e) {
e.printStackTrace();
}
// br and pw are auto-closed (in reverse order)チェック例外と非チェック例外
チェック例外(Exception を継承)は 'throws' で宣言またはキャッチする必要があります — コンパイラが強制します。回復可能な条件(ファイルが見つからない、ネットワークエラー)に使用します。非チェック例外(RuntimeException を継承)は宣言不要です — プログラミングエラー(null ポインタ、無効な引数)に使用します。議論:チェック例外は処理を強制しますがコードを煩雑にします;多くのフレームワークは非チェックを好みます。
// Checked exceptions (must be declared or caught)
public void readFile(String path) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
// IOException is checked — compiler enforces handling
}
// Unchecked exceptions (RuntimeException, no need to declare)
public int divide(int a, int b) {
if (b == 0) {
throw new IllegalArgumentException("Divisor cannot be zero");
// RuntimeException — no 'throws' needed
}
return a / b;
}
// Common checked exceptions:
// IOException, SQLException, ClassNotFoundException
// Common unchecked exceptions:
// NullPointerException, IllegalArgumentException,
// IndexOutOfBoundsException, ArithmeticException,
// ClassCastException, IllegalStateException
// Custom checked exception
class DataException extends Exception {
public DataException(String msg) { super(msg); }
}
// Custom unchecked exception
class ValidationException extends RuntimeException {
public ValidationException(String msg) { super(msg); }
}ファイル I/O(NIO.2)
NIO.2(java.nio.file)はモダンなファイル API です。Files.readString/writeString(Java 11+)はテキストに便利です。Files.lines() は遅延 Stream を返します — 大きなファイルに効率的(try-with-resources で閉じる必要あり)。Path.of() は古い File クラスを置き換えます。Files.createDirectories() はフルパスを作成します。常に IOException を処理してください。
import java.nio.file.*;
import java.io.*;
// Read entire file (small files)
List<String> lines = Files.readAllLines(Path.of("input.txt"));
String content = Files.readString(Path.of("config.json")); // Java 11+
byte[] bytes = Files.readAllBytes(Path.of("image.png"));
// Write file
Files.writeString(Path.of("output.txt"), "Hello, World!");
Files.write(Path.of("data.bin"), bytes);
// Append
Files.writeString(Path.of("log.txt"), "entry\n",
StandardOpenOption.APPEND, StandardOpenOption.CREATE);
// Stream lines (large files, lazy)
try (Stream<String> lineStream = Files.lines(Path.of("large.txt"))) {
lineStream.filter(l -> l.contains("ERROR"))
.forEach(System.out::println);
}
// Copy, move, delete
Files.copy(Path.of("src.txt"), Path.of("dest.txt"));
Files.move(Path.of("old.txt"), Path.of("new.txt"));
Files.delete(Path.of("temp.txt"));
// Check existence
boolean exists = Files.exists(Path.of("file.txt"));
// Create directories
Files.createDirectories(Path.of("a/b/c"));Reader と Writer(テキスト)
BufferedReader/Writer はテキスト I/O に効率的です(バッファリングがシステムコールを削減)。PrintWriter は printf スタイルのフォーマットを提供します。Scanner は入力を解析します(nextInt、nextDouble、nextLine)。InputStreamReader はバイトストリームを文字ストリームにブリッジします(非 UTF-8 の場合は charset を指定)。ストリームが確実に閉じられるように try-with-resources を常に使用してください。
import java.io.*;
import java.nio.file.*;
// BufferedReader (efficient text reading)
try (BufferedReader br = Files.newBufferedReader(Path.of("input.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
// BufferedWriter (efficient text writing)
try (BufferedWriter bw = Files.newBufferedWriter(Path.of("output.txt"))) {
bw.write("First line");
bw.newLine();
bw.write("Second line");
}
// PrintWriter (convenient formatting)
try (PrintWriter pw = new PrintWriter("output.txt")) {
pw.println("Hello");
pw.printf("Name: %s, Age: %d%n", "Alice", 30);
}
// Scanner (parsing input)
try (Scanner sc = new Scanner(Path.of("data.txt"))) {
while (sc.hasNextLine()) {
String line = sc.nextLine();
// Parse tokens
Scanner lineSc = new Scanner(line);
if (lineSc.hasNextInt()) {
int n = lineSc.nextInt();
}
}
}
// InputStreamReader (bytes to chars, e.g., from InputStream)
Reader reader = new InputStreamReader(System.in);日付と時刻(java.time)
java.time(Java 8+)はモダンな日付/時刻 API で、古い Date/Calendar を置き換えます。LocalDate(日付のみ)、LocalTime(時刻のみ)、LocalDateTime(両方)、ZonedDateTime(タイムゾーン付き)。すべて不変でスレッドセーフです。日付差には Period、時間差には Duration を使用します。解析/フォーマットには DateTimeFormatter。機械タイムスタンプ(UTC)には Instant。
import java.time.*;
import java.time.format.*;
import java.time.temporal.*;
// Current date/time
LocalDate today = LocalDate.now(); // 2024-01-15
LocalTime now = LocalTime.now(); // 14:30:45.123
LocalDateTime dt = LocalDateTime.now(); // both
ZonedDateTime zdt = ZonedDateTime.now(); // with timezone
// Create specific
LocalDate date = LocalDate.of(2024, 1, 15);
LocalTime time = LocalTime.of(14, 30, 0);
LocalDateTime specific = LocalDateTime.of(2024, 1, 15, 14, 30);
// Parsing and formatting
LocalDate parsed = LocalDate.parse("2024-01-15");
String formatted = date.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
// "15/01/2024"
// Manipulation (immutable, returns new)
LocalDate tomorrow = today.plusDays(1);
LocalDate lastMonth = today.minusMonths(1);
LocalDate nextYear = today.plusYears(1);
// Period (date-based)
Period age = Period.between(LocalDate.of(1990, 1, 1), today);
System.out.println(age.getYears()); // 34
// Duration (time-based)
Duration dur = Duration.between(time, LocalTime.now());
System.out.println(dur.toMinutes());
// Instant (machine time, UTC)
Instant instant = Instant.now();
Instant epoch = Instant.ofEpochSecond(0);並行性の基礎
Java の並行性:Thread(低レベル)、ExecutorService(スレッドプール — 推奨)、CompletableFuture(非同期合成、Promise のような)。parallelStream() は並列処理に ForkJoinPool を使用します。synchronized ブロックは共有状態を保護します。Atomic 変数(AtomicInteger など)はロックフリーのスレッドセーフ操作を提供します。複雑な並行性には java.util.concurrent コレクション(ConcurrentHashMap、BlockingQueue)を使用します。
import java.util.concurrent.*;
// Create a thread
Thread thread = new Thread(() -> {
System.out.println("Running in: " + Thread.currentThread().getName());
});
thread.start();
thread.join(); // wait for completion
// ExecutorService (thread pool)
ExecutorService executor = Executors.newFixedThreadPool(4);
Future<Integer> future = executor.submit(() -> {
Thread.sleep(1000);
return 42;
});
Integer result = future.get(); // blocks until done
executor.shutdown();
// CompletableFuture (async, Java 8+)
CompletableFuture<String> cf = CompletableFuture
.supplyAsync(() -> "Hello")
.thenApply(s -> s + " World")
.thenApply(String::toUpperCase);
String asyncResult = cf.join(); // "HELLO WORLD"
// Parallel stream
List<Integer> nums = List.of(1, 2, 3, 4, 5);
int sum = nums.parallelStream().mapToInt(Integer::intValue).sum();
// Synchronized
synchronized (this) {
// only one thread at a time
}
// Atomic variables
AtomicInteger counter = new AtomicInteger(0);
counter.incrementAndGet();
counter.compareAndSet(0, 1);Lambda 式
Lambda 構文の基礎
Lambda(Java 8+)は関数型インターフェースの簡潔な実装です。構文:(params) -> expression または (params) -> { statements; }。コンパイラはターゲット型からパラメータ型を推論します。単一パラメータの lambda は括弧を省略でき、ゼロパラメータは空の括弧が必要です。Lambda は関数型プログラミングを可能にし、Streams API の基盤です。