Java 標準ユーティリティ:Arrays クラスと Objects クラスの活用

java.util.Arrays クラスの主要機能

配列操作におけるボイラープレートコードを削減するため、Java 標準ライブラリは java.util.Arrays クラスを提供しています。このクラスには、配列の作成、比較、排序、検索などに関する静的メソッドが揃っています。

配列の複製と初期化

既存の配列を基に新しい配列を作成するには、以下のメソッドが利用できます。

  • copyOf(original, newLength):配列をコピーし、必要に応じて長さを調整します。新しい長さが元の配列より大きい場合、剩余部分は型に応じた初期値(null または 0)で埋められます。
  • copyOfRange(original, from, to):指定された範囲 [from, to) の要素のみを抽出して新しい配列を生成します。
  • fill(array, value):配列の全要素を指定された値で一括埋めします。

比較とハッシュコード

配列の内容に基づく比較やハッシュ値の生成が可能です。

  • equals(arr1, arr2):二つの配列が同じ長さであり、対応する要素がすべて等しいかを判定します。
  • hashCode(array):配列の内容に基づいたハッシュコードを返します。コレクションのキーとして配列を使用する際に有用です。

排序と検索

配列の排序および要素の探索機能も提供されています。

  • sort(array):配列を昇順に排序します。プリミティブ型には Dual-Pivot Quicksort、オブジェクト型には TimSort が採用されています。
  • binarySearch(array, key):排序済みの配列に対して二分探索を行い、要素のインデックスを返します。対象が見つからない場合は負の値が返されます。
  • binarySearch(array, key, comparator):カスタム比較器を用いて探索を行います。

ストリーム化と文字列化

配列を他の形式に変換する utility も用意されています。

  • stream(array):配列を Stream インターフェースに変換し、関数型処理を可能にします。範囲指定版 stream(array, from, to) も存在します。
  • toString(array):配列の内容を [elem1, elem2, ...] 形式の文字列に変換します。デフォルトの toString ではアドレスしか表示されないため、デバッグに便利です。
  • asList(array):配列を固定サイズのリストビューとして扱います。サイズ変更が必要な場合は new ArrayList<>(Arrays.asList(array)) のようにラップする必要があります。

関数型操作

Java 8 以降では、関数型インターフェースを利用した高度な操作もサポートされています。

  • setAll(array, generator):インデックスを引数とする関数を用いて、配列の各要素を生成します。
int[] values = new int[5];
Arrays.setAll(values, index -> index * 5);
// 結果:[0, 5, 10, 15, 20]
  • parallelPrefix(array, operator):並列処理を用いて累積計算を行います。各要素は、それ以前の要素の累積結果と現在の要素との演算結果で更新されます。
int[] data = {1, 2, 3, 4};
Arrays.parallelPrefix(data, (left, right) -> left + right);
// 結果:[1, 3, 6, 10]

java.util.Objects クラスによる null 安全な処理

java.util.Objects クラスは、オブジェクト操作における null 参照例外(NullPointerException)のリスクを低減し、コードの可読性を向上させるための静的メソッド群です。

主要メソッドの一覧

カテゴリ メソッド 概要 使用例
null 判定 isNull(obj) 対象が null かどうかを確認 Objects.isNull(target)
nonNull(obj) 対象が null でないことを確認 Objects.nonNull(target)
例外送出 requireNonNull(obj) null の場合、NullPointerException をスロー Objects.requireNonNull(input)
requireNonNull(obj, msg) カスタムメッセージ付きで例外をスロー Objects.requireNonNull(input, "必須項目")
等値比較 equals(a, b) null 安全な等値比較 Objects.equals(str1, str2)
deepEquals(a, b) 配列を含む深層比較 Objects.deepEquals(arr1, arr2)
ハッシュ生成 hashCode(obj) null 許容のハッシュコード取得 Objects.hashCode(name)
hash(values...) 複数フィールドからハッシュを生成 Objects.hash(id, name)
文字列化 toString(obj) null の場合 "null" を返す Objects.toString(value)
toString(obj, default) null の場合、デフォルト値を返す Objects.toString(value, "N/A")

実装例と注意点

コンストラクタやメソッドの引数検証において、requireNonNull を使用することで、早期にエラーを検知できます。

public void process(String input) {
    Objects.requireNonNull(input, "入力データは必須です");
    // 処理 continued...
}

オブジェクトの等値比較では、片方が null であっても例外を投げずに false を返す Objects.equals が安全です。

String val1 = "test";
String val2 = null;
boolean result = Objects.equals(val1, val2); // false

entity クラスなどで equalshashCode をオーバーライドする際、フィールドの比較にこのクラスを利用すると実装が簡潔になります。

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    User user = (User) o;
    return id == user.id && Objects.equals(name, user.name);
}

@Override
public int hashCode() {
    return Objects.hash(id, name);
}

配列の比較においては、Arrays.equals が一次元配列用、Objects.deepEquals が多次元配列用として使い分けられます。

int[] nums1 = {10, 20};
int[] nums2 = {10, 20};
System.out.println(Objects.deepEquals(nums1, nums2)); // true

String[][] matrix1 = {{"A"}, {"B"}};
String[][] matrix2 = {{"A"}, {"B"}};
System.out.println(Objects.deepEquals(matrix1, matrix2)); // true

ソート処理におけるカスタム比較でも、null 安全な比較器と組み合わせることで安定した動作を確保できます。

Comparator<Person> comp = Comparator.comparingInt(p -> p.age);
int comparison = Objects.compare(personA, personB, comp);

タグ: java-util arrays-class objects-class null-safety java-se

6月10日 23:16 投稿