Featured image of post 久々のJavaの備忘録

久々のJavaの備忘録

目次

背景

  • SpringでAPIを管理する必要があった
  • Javaは十年ぶりなので備忘録をまとめた

Javaとは

Javaのエディション

  • Java SE(Java Platform, Standard Edition)
    • 標準的なエディション
  • Java EE(Java Platform, Enterprise Edition)
    • 企業向け大規模エディション
  • Java ME(Java Platform, Micro Edition)
    • 組み込み向けエディション

なお、Java 9 以降はJava EE は Jakarta EE の名称に変更された。
開発の管理は、OracleからEclipse Foundationになった。

JDKとJRE

  • JRE(Java Runtime Environment)
    • Javaの実行環境
  • JDK(Java Development Kit)
    • Javaの開発環境。JREを含む

Oracle JDKとOpenJDK

  • Oracle JDKは最初は無償だったが2018年に有償化された
  • OpenJDKは、Oracleの他、Red Hat、IBM、Apple、SAPなども参加するコミュニティで開発

文法

リテラル

リテラルは次の4つ。

  • 数字リテラル
    • 整数リテラル: int型として扱われるが、接尾辞を付けることでlong型としても扱える(例:123L
    • 浮動小数点リテラル: double型として扱われるが、接尾辞を付けることでfloat型としても扱える(例:1.23f
  • 文字・文字列リテラル
    • 文字リテラル: 単一のUnicode文字を表現し、char型として扱われる(例: 'あ'
    • 文字列リテラル: 複数の文字を連結したものを表現し、String型として扱われる(例: "あ"
    • テキストブロック: Java 13以降で導入され、複数行の文字列を簡単に扱うことができる(例: """あ"""
  • 論理値リテラル
    • boolean型として扱われ、trueまたはfalseの値を取る
  • 特殊リテラル
    • nullリテラル: オブジェクト参照が存在しないことを示し、nullとして扱われる

プリミティブ

プリミティブ型(基本データ型)の一覧は以下。

種別説明
論理値boolean真偽値。true または false。
文字char2バイトUNICODE文字。'\u0000'~'\uffff'。
整数byte1バイト符号付整数。-128~127。
short2バイト符号付整数。-32768~32767。
int4バイト符号付整数。-2147483648~2147483647。
long8バイト符号付整数。約-922京~約922京。
浮動小数float4バイト浮動小数点数。
double8バイト浮動小数点数。

列挙型

Java5からサポートされた列挙型。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public enum Day {
    SUNDAY,
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY
}

Day today = Day.WEDNESDAY;
System.out.println("Today is " + today);

引数を設定する事もできる。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public enum Day {
    SUNDAY(true),
    MONDAY(false),
    TUESDAY(false),
    WEDNESDAY(false),
    THURSDAY(false),
    FRIDAY(false),
    SATURDAY(true);

    private final boolean isWeekend;

    Day(boolean isWeekend) {
        this.isWeekend = isWeekend;
    }

    public boolean isWeekend() {
        return isWeekend;
    }
}

Day today = Day.WEDNESDAY;
System.out.println("Today is " + today);

if (today.isWeekend()) {
    System.out.println(today + " is a weekend day.");
} else {
    System.out.println(today + " is a weekday.");
}

型の調べ方

instanceofを使う方法

1
2
3
4
Object obj = "Hello, World!";
if (obj instanceof String) {
    System.out.println("The variable is of type String.");
}

getClassを使う方法

1
2
Object obj = "Hello, World!";
System.out.println("The type of obj is: " + obj.getClass().getName());

その他にはReflectionを使う方法もある。

キャスト

値型(プリミティブ型)

明示的なキャスト(大きな型から小さな型)

1
2
double d = 123.45;
int j = (int) d;

暗黙的なキャスト(小さな型から大きな型)

1
2
int j = 123;
double d = j;

参照型(オブジェクト)

アップキャスト(サブクラスからスーパークラスへ)される。

1
Animal animal = new Dog(); 

ダウンキャスト(スーパークラスからサブクラスへ)は明示的に型を指定する。

1
2
Animal animal = new Dog(); 
Dog dog = (Dog) animal; 

ボクシング

Boxingは、基本データ型(int、double、booleanなど)を、対応するラッパークラス(Integer、Double、Booleanなど)に変換すること。

1
2
int primitiveInt = 10;
Integer wrapperInt = Integer.valueOf(primitiveInt);

メソッドやコレクションの要素は、ラッパークラスを使うことが推奨される。

1
2
ArrayList<Integer> list = new ArrayList<>();
list.add(20); // Boxing: int -> Integer

修飾子

修飾子一覧

以下が修飾子一覧。

修飾子クラスインタフェースメソッドコンストラクタブロック変数説明
public×アクセス修飾子
protected×××アクセス修飾子
private×××アクセス修飾子
static××××スタティック修飾子
final×××ファイナル修飾子
abstract×××抽象修飾子
native×××××ネイティブ修飾子
synchronized××××同期修飾子
transient×××××一時的修飾子
volatile×××××揮発性修飾子
strictfp×××厳密浮動小数修飾子

アクセス修飾子

Javaはアクセス修飾子による制限は、パッケージの階層に関係なく同一パッケージか異なるパッケージかで決まる。

アクセス修飾子自クラス同パッケージサブクラス(同パッケージ)他クラス(同パッケージ)サブクラス(他パッケージ)他クラス(他パッケージ)
public
protected×
なし(package-private)××
private×××××

なお、interfaceはデフォルトでabstructであり、メソッドはデフォルトでpublic abstructになっている。

1
2
3
public interface XXXInterface {
    void testFunction(int a); // メソッドは自動的にpublic abstractになる
}

const

実質的に、final + static = const

1
public static final int CONSTANT_VALUE = 42;

クラス

クラス

クラスは、オブジェクト(インスタンス とも)が持つ、フィールド(属性、アトリビュート、プロパティ、メンバ変数)や、メソッド(関数、メンバ関数)などを定義する。

1
2
3
4
class TestClass {
    TypeName FieldName;
    TypeName MedhotdName(Args) { ... }
}

インスタンス化

1
TestClass o = new TestClass();

コンストラクタはあるがデストラクタはない。

1
2
3
4
5
6
class Person {
    String myName;
    Person(String myName) {
        this.myName = myName;
    }
}

クラス修飾子

  • クラスの修飾子には、public、final、abstract、strictfp を指定することができる
  • インナークラスでは、protected、private、static を指定することが可能となる

継承

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class SuperClass {
    void method1() { System.out.println("method1"); }
}

class SubClass extends SuperClass {
    void method2() { System.out.println("method2"); }
}

SubClass o = new SubClass();
o.method1(); 
o.method2();

superで親クラスを呼び出せる。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class SuperClass {
    String name;
    SuperClass(String name) { this.name = name; }
    void printName() { System.out.println(this.name); }
}

class SubClass extends SuperClass {
    SubClass(String name) {
        super(name); // 親クラスのコンストラクタを呼び出す
        System.out.println(super.name); // 親クラスのフィールドを参照する
        super.printName();  // 親クラスのメソッドを呼び出す
    }
}

インスタンスが、指定したクラスまたはその上位のクラスに属しているかどうかはinstanceofを使う。

1
2
3
4
SubClass obj = new SubClass();
if (obj instanceof SuperClass) {
    System.out.println("属してます");
}

匿名内部クラス

次の場面では、クラスに名前をつけること無くクラスを定義してインスタンスを生成する事が可能

  • あるクラスの派生クラスのオブジェクトを一つだけインスタンス化する場合
  • あるインターフェイスを実装して一つだけインスタンスを作成する場合

1
2
3
4
5
6
7
8
9
public interface MyInterface1 {
  void foo();
}

MyInterface1 mi = new MyInterface1() {
  public void foo() {
    System.out.println("Hello, anon class!");
  }
}

ジェネリクス

ジェネリクスの例

任意の型を受け付けるクラス・メソッドに対して特定の型を割り当てて、型専用のクラスを生成する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class Test<T> {
    T value;
    Test(T value) {
        this.value = value;
    }
}

Test<String>t1 = new Test<String>("ABC");
Test<Integer>t2 = new Test<Integer>(123);
System.out.println(t1.value);
System.out.println(t2.value);

ジェネリクスの用語

用語説明
ジェネリック型(generic type)List<T>型引数を持つクラスやインタフェース。
仮型パラメータ(type parameter)Tジェネリック型の宣言時に使われる型のプレースホルダー。
パラメータ化された型(parameterized type)List<String>実際の型引数を使用してインスタンス化されたジェネリック型。
実型パラメータ(actual type parameter)Stringパラメータ化された型の具体的な型引数。
原型(raw type)List型引数を使用しないジェネリック型。非ジェネリック型と同様に扱われる。
境界型パラメータ(bounded type parameter)<E extends Number>特定のクラスやインタフェースを拡張または実装する型に制限された型パラメータ。
非境界ワイルドカード型(unbounded wildcard type)List<?>任意の型を許容するワイルドカード型。
境界ワイルドカード型(bounded wildcard type)List<? extends Number>, List<? super Number>特定のクラスやインタフェースを拡張する型を許容するワイルドカード型。

原型の注意

  • なお、原型ではコンパイラによる型安全性は提供されない
  • そのため、原型よりも非境界型ワイルドカードを利用することが推奨されている
  • 原型がJavaに残っているのは、Java 4以前への後方互換性を維持するため

ワイルドカード型

3つのワイルドカード型

Javaには次の3つのワイルドカード型(<?>)がある。

  • 非境界ワイルドカード型 (unbounded wildcard type)
    • 具体例:List<?> list
  • 境界ワイルドカード型 (bounded wildcard type)
    • 上限境界ワイルドカード型 (upper bounded wildcard type)
      • 具体例:List<? extends Number> list
    • 下限境界ワイルドカード型 (lower bounded wildcard type)
      • 具体例:List<? super Number> list

ジェネリック型の継承関係

Javaでは型パラメータ同士に継承関係があっても、ジェネリックス型自体には継承関係はない。

ジェネリクス型の継承関係

このジェネリックス型の性質(変性)を不変という。

1
2
3
ArrayList<Number> numbers = new ArrayList<Number>(); // => 問題無し

numbers = new ArrayList<Object>(); // => コンパイルエラー

非境界ワイルドカード型

しかし、非境界ワイルドカード型はすべてのパラメータ化された型のスーパータイプとなる。

非境界ワイルドカード型

そのため、どんなListも、List<?>に代入できる。

1
2
3
ArrayList<?> list = new ArrayList<Number>(); // => 問題無し

list = new ArrayList<Object>(); // => 問題無し

これがワイルドカード型の正体。

非境界ワイルドカード型の制限

非境界ワイルドカード型は、任意のパラメータ化された List のスーパータイプとなり便利に利用できる一方、以下のような制限がある。

  • メソッドの戻り値に使われているTはObject型になる
  • メソッドの引数に使われているTにはnullリテラルしか渡せない
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
static class Holder<T> {
    private T value;

    public Holder(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }   
}

getValueの例

1
2
3
4
5
6
7
8
9
Holder<?> holder = new Holder<String>("Value");

String string = holder.getValue();
// => コンパイルエラー
// 非境界ワイルドカード型は型パラメータが不明なため、型パラメータを String だと保障できない

Object object = holder.getValue();
// => 問題なし
// 非境界ワイルドカード型は型パラメータが不明なため何が入っているか分からないが、すべての参照型のスーパータイプである Object なら絶対に ClassCastException は発生しないため
  • 非境界ワイルドカード型のメソッドの戻り値として許されるのは Object のみという事
  • 何が入っているかは分からないが、すべての参照型は Object のサブタイプであるから

次はsetValueの例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
Holder<?> holder = new Holder<String>();

holder.setValue(new String("String"));
// => コンパイルエラー
// 非境界ワイルドカード型は型パラメータが不明なため、String を this.value に代入可能だと保障できない
// たとえば、this.value は Integer 型かもしれない。

holder.setValue(new Object());
// => コンパイルエラー
// 非境界ワイルドカード型は型パラメータが不明なため、Object を this.value に代入可能だと保障できない
// たとえば、this.value は Integer 型かもしれない。

holder.setValue(null);
// => 問題なし
// 非境界ワイルドカード型は型パラメータが不明なため this.value の型が何か分からないが、null はどんな変数にも代入できるので ClassCastException は発生しない
  • 非境界ワイルドカード型のメソッドの引数に使われているT型にはnullリテラルしか代入できない
  • なぜなら、nullはJavaの仕様上、null型という特殊な型の唯一の値であり、どんな参照型の変数に代入できることが定められているから

境界型ワイルドカード型

境界ワイルドカード型はパラメータ化されたそのジェネリックス型の一部のスーパータイプの事。

ObjectとNumberとIntegerの階層

このとき、境界型ワイルドカードは以下のように定義される。

  • 上限境界
    • ある型のサブタイプでパラメータ化された、そのジェネリックス型のスーパータイプ
    • 具体例:List<? extends Number>
      • Numberのサブタイプでパラメータ化されたListのスーパータイプとなる型
  • 下限境界型
    • ある型のスーパータイプでパラメータ化された、そのジェネリックス型のスーパータイプ
    • 具体例:List<? super Number>
    • Numberのスーパータイプでパラメータ化されたListのスーパータイプとなる型

上限境界型の性質は次の図となる。

上限境界型

一方、下限境界型の性質は次の図となる。

下限境界型

コードとしては次となる。

1
2
3
4
5
6
7
Holder<? extends Number> upper1 = new Holder<Object>(); // => コンパイルエラー
Holder<? extends Number> upper2 = new Holder<Number>(); // => 問題なし
Holder<? extends Number> upper3 = new Holder<Integer>(); // => 問題なし

Holder<? super Number> lower1 = new Holder<Object>(); // => 問題なし
Holder<? super Number> lower2 = new Holder<Number>(); // => 問題なし
Holder<? super Number> lower3 = new Holder<Integer>(); // => コンパイルエラー

境界型ワイルドカード型の制限

境界ワイルドカード型を使うと、型安全のために存在している非境界ワイルドカード型の制限を緩和することができる。

上限境界型のメリット

  • 「メソッドの戻り値に使われているTObject型になる」という制限が緩和される
  • つまり、「メソッドの戻り値に使われているTNumber型になる」
  • 理由
    • 上限境界型ワイルドカード(<? extends Number>)は、指定された型Tまたはそのサブタイプを表す
    • そのため、コンパイラはその型がNumber型またはそのサブタイプであることを保証できる

下限境界型のメリット

  • 「メソッドの引数に使われている Tにはnullリテラルしか渡せない」という制限が緩和される
  • つまり、「メソッドの引数に使われているTにはNumberが渡せる」
  • 理由
    • 限境界型ワイルドカード(<? super Number>)は、指定された型Tまたはそのスーパータイプを表す
    • そのため、Number型またはそのスーパータイプ(Object等)のオブジェクトを引数として渡すことができる

これが境界型ワイルドカード型の利点。

変性

3つの変性

変性(variance)とは、ジェネリクスにおいて、異なる型パラメータを持つ型の間で、代入の可能性や互換性を表す概念。

変性
共変/共変性(Covariance)List<Integer>List<Number>のサブタイプ
反変/反変性(Contravariance)List<Number>List<Integer>のサブタイプ
非変/非変性(Invariance)List<Number>List<Integer>の継承関係はない

NOTE: IntegerクラスはNumberクラスのサブクラス

  • Javaは非変タイプのジェネリクスになる
  • つまり、List<Integer>List<Number>のサブクラスとはならない
  • 故に、下のコードはコンパイルエラーになる
1
2
3
4
List<Integer> intList = new ArrayList<>();
List<Number> numList = new ArrayList<>();

numList = intList; // コンパイルエラー       

Put/Get 原則

このPut/Getの原則は、共変性(covariance)と反変性(contravariance)をどのように適用するかを説明するための用語。

  • PECS(Producer Extends, Consumer Super):
    • Producer Extends: 何かを生成する(出力する)場合は、extends キーワードを使う
    • Consumer Super: 何かを消費する(入力する)場合は、super キーワードを使う

Producer Extendsパターン

1
2
3
4
5
public void processNumbers(List<? extends Number> list) {
    for (Number number : list) {
        System.out.println(number);
    }
}

Consumer Superパターン

1
2
3
4
public void addNumbers(List<? super Integer> list) {
    list.add(1);
    list.add(2);
}

レコードクラス

レコードクラス

Java 16 でサポートされた機能で、下記の特徴を持つクラスを生成する

  • コンストラクタで指定した値をイミュータブル(変更不可)なフィールドとして保持する
  • フィールド名と同じアクセッサメソッドを持つ
  • toString(), equals(), hashCode() メソッドを持つ
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
final class Book {
    private final String title;
    private final String author;

    public Book(String title, String author) {
        this.title = title;
        this.author = author;
    }

    public String title() {
        return title;
    }

    public String author() {
        return author;
    }

    @Override
    public String toString() {
        return "Book [title=" + title + ", author=" + author + "]";
    }

    @Override
    public boolean equals(Object o) {
        return (this.title == ((Book)o).title) && (this.author == ((Book)o).author);
    }

    @Override
    public int hashCode() {
        return super.hashCode();
    }
}

上のコードは下と同じ

1
record Book (String title, String author) { }

lombok

lombokのアノテーションでもrecordクラスと同じ事ができるので、それでも良い。

1
2
3
4
5
6
7
import lombok.Data;

@Data
public class User {
    private String name;
    private int age;
}

これは次のコードと同等の定義となる。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import java.util.Objects;

public class User {
    private String name;
    private int age;

    // デフォルトコンストラクタ
    public User() {}

    // コンストラクタ
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // GetterとSetter
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    // equalsメソッドのオーバーライド
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        User user = (User) obj;
        return age == user.age && Objects.equals(name, user.name);
    }

    // hashCodeメソッドのオーバーライド
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    // toStringメソッドのオーバーライド
    @Override
    public String toString() {
        return "User{name='" + name + "', age=" + age + "}";
    }
}

ラムダ式

ラムダ式

Java 8 で ラムダ式 がサポートされた。

1
2
3
4
5
6
7
8
9
class LocalClass implements Runnable {
    @Override
    public void run() {
        System.out.println("Hello!");
    }
}

Runnable r = new LocalClass();
r.run();

上のコードは下のlambda式でかける。

1
2
3
4
Runnable r = () -> {
    System.out.println("Hello!");
};
r.run();

JavaのLambdaは、単一の抽象メソッドを持つインタフェースを実装した無名クラスのインスタンスを生成する式となる。

関数型インタフェース

関数型インタフェースは「抽象メソッドをひとつのみ持つインタフェース」の事。

1
2
3
4
@FunctionalInterface
interface MyFunctionalInterface {
    public abstract int run(String arg);
}

下のように使える。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Function<String, Integer> strLength = (str) -> { return str.length(); };
int len = strLength.apply("ABC");
System.out.println(len);

BiFunction<String, Integer, Character> charAt = (str, n) -> { return str.charAt(n); };
char c = charAt.apply("ABCDEFG", 3);
System.out.println(c);

BiPredicate<String, String> strEqual = (str1, str2) -> { return str1 == str2; };
boolean b = strEqual.test("ABC", "ABC");
System.out.println(b);

関数型インターフェイスのまとめ。

関数型インタフェース引数の型戻り値の型メソッド名説明
Function<T, R>TRR apply(T t)T型の引数を受け取り、R型の戻り値を返す。
BiFunction<T, U, R>T, URR apply(T t, U u)T型とU型の2つの引数を受け取り、R型の戻り値を返す。
UnaryOperator<T>TTT apply(T t)T型の引数を1つ受け取り、T型の戻り値を返す(Function<T, T>のサブインタフェース)。
BinaryOperator<T>T, TTT apply(T t1, T t2)T型の引数を2つ受け取り、T型の戻り値を返す(BiFunction<T, T, T>のサブインタフェース)。
Consumer<T>Tなしvoid accept(T t)T型の引数を受け取り、値を返さない。
BiConsumer<T, U>T, Uなしvoid accept(T t, U u)T型とU型の2つの引数を受け取り、値を返さない。
Predicate<T>Tbooleanboolean test(T t)T型の引数を受け取り、真偽を返す。
BiPredicate<T, U>T, Ubooleanboolean test(T t, U u)T型とU型の2つの引数を受け取り、真偽を返す。
Supplier<R>なしRR get()引数を受け取らず、R型の戻り値を返す。

インターフェイス

インタフェース修飾子

  • インタフェースの修飾子には、public、abstract、strictfp を指定することができる
  • インタフェースをクラス内に定義する場合には protected、private、static を指定することも可能

継承と実装

継承

1
2
3
public interface ActionListener extends EventListener {
    public void actionPerformed(ActionEvent e);
}

実装

1
2
3
4
5
class Test implements InterfaceA {
    public void methodA(String msg) {
        System.out.println(msg);
    }
}

Java8以降のinterface

Java 8以降は、インターフェースはデフォルトメソッド(default)や静的メソッド(static)を持つことができるようになった。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public interface MyInterface {
    void myMethod();

    // デフォルトメソッド
    default void defaultMethod() {
        System.out.println("This is a default method.");
    }

    // 静的メソッド
    static void staticMethod() {
        System.out.println("This is a static method.");
    }
}

抽象クラス

抽象クラス vs. Interface

そうすると、abstruct classとの違いは何かと言うと次になる。

  • 継承:
    • インターフェース: 多重継承が可能
    • 抽象クラス: 単一継承のみ
  • フィールド:
    • インターフェース: インスタンスフィールドを持てない(static finalのみ)
    • 抽象クラス: インスタンスフィールドを持てる
  • メソッドの実装:
    • インターフェース: デフォルトメソッドを持てるが、基本的にはメソッドのシグネチャのみを定義
    • 抽象クラス: 具象メソッドと抽象メソッドの両方を持てる
  • コンストラクタ:
    • インターフェース: 持てない
    • 抽象クラス: 持てる

使用感としては次になる。

  • インターフェースを使用する場合:
    • クラス間で共通の契約や振る舞いを定義したい
    • 多重継承が必要な場合
    • 既存のクラスに新しい振る舞いを追加したい
  • 抽象クラスを使用する場合:
    • 部分的な実装を提供したい
    • クラス群に共通の状態や動作を持たせたい
    • コンストラクタや状態を持つ必要がある場合

抽象クラス vs. 具象クラス

  • 抽象クラスを使用する場合:
    • 部分的な実装や共通の状態・動作を提供する必要があるとき
    • 基底クラスとしてのみ使用され、インスタンス化されないことを意図するとき
    • テンプレートメソッドパターンを実装するとき
  • 具象クラスを使用する場合:
    • 完全な実装を持ち、直接インスタンス化されることを意図するとき
    • 他のクラスや抽象クラスに依存せず、独立して機能するクラスを定義するとき
    • 特定のオブジェクトの具体的なインスタンスを作成するとき

コレクション

代表的なコレクション

次のようなコレクションが代表的。

カテゴリクラス説明
List系ArrayList動的配列を扱う。ランダムアクセスが高速だが、挿入・削除はリストの末尾以外では遅くなることがある
LinkedList双方向連結リストを扱う。挿入・削除が高速ですが、ランダムアクセスは遅くなる
Vector動的配列を扱う。スレッドセーフだが、パフォーマンスが悪いため、現在ではあまり推奨されない古いクラス
Set系HashSet値の重複を許さない順不同の要素集合を扱う。内部的にハッシュテーブルを使用している
TreeSet値の重複を許さないソートされた要素集合を扱う。内部的に赤黒木を使用する
Map系HashMapキーと値の組からなる要素の集合を扱う。順序は保証されない。内部的にハッシュテーブルを使用している
LinkedHashMapキーと値の組からなる要素の集合を扱う。挿入順序が保証されいる
TreeMapキーと値の組からなる要素の集合を扱う。キーでソートされている。内部的に赤黒木を使用している
Queue系Deque両端からの挿入・削除が可能なキューやスタックを扱う。Dequeはインタフェースであり、ArrayDequeLinkedListがその実装クラス

パッケージ

Import

  • import文を使用することで、繰り返し書く必要がなくなるのが目的
  • 故に、importを使わずとも、クラスの完全修飾名でアクセスすればアクセスできる
  • 当然、同一packageからは、そのままアクセスできる
1
2
3
4
java.util.ArrayList<String> list = new java.util.ArrayList<>();
list.add("Hello");
list.add("World");
System.out.println(list);

例外

例外のクラス

以下のようなタイプのエラーがある。

クラス説明
ErrorJava仮想マシン(JVM)によって検出される致命的なエラー。通常、プログラムで回復不可能であり、例外ハンドラを記述しても処理を継続できないことが多い。例:OutOfMemoryError(メモリ枯渇)、StackOverflowError(スタックオーバーフロー)など
RuntimeException実行時に発生するプログラムエラー。チェックされない例外(Unchecked Exception)であり、例外ハンドラは省略可能。例:ArithmeticException(ゼロ除算)、IllegalArgumentException(引数不正)、NullPointerException(NULLポインタ参照)、ArrayIndexOutOfBoundsException(不正インデックスによる配列参照)など
Exception一般的な例外。チェックされる例外(Checked Exception)であり、例外ハンドラを記述しないとコンパイルエラーとなる。例:IOExceptionSQLExceptionなど

検査例外と非検査例外

  • 検査例外(Checked Exception)はコンパイル時にチェックされる例外
  • プログラムの外部的な要因(例えば、ファイルの存在しないことや、ネットワークの障害など)によって発生する可能性のある問題を扱う

下のように検査例外である、IOExceptionなどをtry-catchで捕まえないといけない。さもなければメソッドでthrowsする必要がある。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 try {
     FileReader reader = new FileReader("nonexistentfile.txt");
     BufferedReader bufferedReader = new BufferedReader(reader);
     String line = bufferedReader.readLine();
     System.out.println(line);
     bufferedReader.close();
 } catch (FileNotFoundException e) {
     System.out.println("File not found: " + e.getMessage());
 } catch (IOException e) {
     System.out.println("IO error: " + e.getMessage());
 }
  • 検査例外は処理の奥深く(例えばDB付近)で発生し、上部(例えばAPIのController)でハンドルする場合、
  • 中間で例外をthrowsでバケツリレーしなければならない時は、非検査例外を使うのがベター
  • もしくは、下のようにエラーを変換する
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// カスタム非検査例外
public class DatabaseException extends RuntimeException {
    public DatabaseException(String message, Throwable cause) {
        super(message, cause);
    }
}

// データベース層のメソッド
public void fetchData() {
    try {
        // データベース操作
    } catch (SQLException e) {
        throw new DatabaseException("Database error occurred", e);
    }
}

// サービス層のメソッド
public void processData() {
    fetchData(); // DatabaseExceptionがスローされる可能性あり
}

// コントローラー層のメソッド
public void handleRequest() {
    try {
        processData();
    } catch (DatabaseException e) {
        // 例外処理(ログ出力、エラーレスポンスの返却など)
    }
}

参考文献

Built with Hugo
テーマ StackJimmy によって設計されています。