「最小値取得」は“いちばん小さいものを安全に一発で取り出す”ユーティリティ
業務コードでは、「最小値」が欲しい場面もかなり多いです。
最小金額、最古の日付、最小スコア、最小バージョン番号…。
毎回 for 文で
int min = Integer.MAX_VALUE;
for (int v : values) {
if (v < min) {
min = v;
}
}
Javaと書いても動きますが、
null や空コレクション、オブジェクトの比較などが絡むと、
一気にバグりやすく、読みにくくなります。
そこで「最小値取得」をユーティリティとして切り出しておくと、
“最小値をどう扱うか”のルールを一箇所に閉じ込められます。
以降は、「最小値を取りたい」と思ったときに、そのユーティリティを呼ぶだけで済む世界を目指します。
基本形:数値 List から最小値を取得する
Stream を使った最小限の書き方
まずは、List<Integer> から最小値を取りたいケースです。
import java.util.List;
public class MinBasic {
public static void main(String[] args) {
List<Integer> scores = List.of(70, 85, 90);
int min = scores.stream()
.mapToInt(Integer::intValue)
.min()
.orElse(0); // 空なら 0 とする
System.out.println(min); // 70
}
}
Javaここで押さえてほしいポイントは二つあります。
一つ目は、mapToInt で「int 専用のストリーム」に変換してから min() を呼んでいることです。min() は「最小値を計算する」メソッドですが、
データが一件もない場合は「最小値が存在しない」ので OptionalInt を返します。
二つ目は、orElse(0) で「空だったときのデフォルト値」を決めていることです。
ここをどうするか(0にするのか、例外にするのか、nullにするのか)は、
プロジェクト全体でルールを決めておくと、コードがブレません。
最小値取得をユーティリティメソッドにまとめる
「null や空 List をどう扱うか」を一箇所に閉じ込める
同じような最小値取得を何度も書くなら、
ユーティリティにしてしまうとスッキリします。
import java.util.List;
public final class Mins {
private Mins() {}
public static int minIntOrDefault(List<Integer> source, int defaultValue) {
if (source == null || source.isEmpty()) {
return defaultValue;
}
return source.stream()
.mapToInt(Integer::intValue)
.min()
.orElse(defaultValue);
}
}
Java使い方はこうなります。
List<Integer> scores = List.of(70, 85, 90);
int min = Mins.minIntOrDefault(scores, 0); // 空なら 0
System.out.println(min); // 70
Javaここでの重要ポイントは、「null と空 List の扱いをユーティリティ側で決めている」ことです。
呼び出し側は「最小値が欲しい」「空なら 0 でいい」とだけ考えればよく、null チェックや Optional の扱いを毎回書かなくて済みます。
オブジェクト一覧から「特定の項目の最小値」を取得する
例:商品一覧から「最小価格」を取り出す
業務では、単なる List<Integer> よりも、
「オブジェクトの特定のフィールドの最小値」が欲しいことが多いです。
class Item {
private final String name;
private final int price;
public Item(String name, int price) {
this.name = name;
this.price = price;
}
public String getName() { return name; }
public int getPrice() { return price; }
}
Javaこれを集計するユーティリティは、こう書けます。
import java.util.List;
import java.util.function.ToIntFunction;
public final class Mins {
private Mins() {}
public static <T> int minIntOrDefault(
List<T> source,
ToIntFunction<? super T> mapper,
int defaultValue
) {
if (source == null || source.isEmpty()) {
return defaultValue;
}
return source.stream()
.mapToInt(mapper)
.min()
.orElse(defaultValue);
}
}
Java使い方はこうです。
List<Item> items = List.of(
new Item("A", 100),
new Item("B", 250),
new Item("C", 180)
);
int minPrice = Mins.minIntOrDefault(items, Item::getPrice, 0);
System.out.println(minPrice); // 100
Javaここで深掘りしたい重要ポイントは三つです。
一つ目は、「ToIntFunction<? super T> mapper が“どの項目を最小化するか”を表している」ことです。Item::getPrice を渡すことで、「価格の最小値が欲しい」という意図が明確になります。
二つ目は、「ユーティリティ側は“どう最小値を計算するか”だけを知っていて、“何を最小化するか”は呼び出し側が決める」構造になっていることです。
これにより、同じメソッドで「価格」「数量」「スコア」など、何でも最小値を取れます。
三つ目は、「空や null の扱いを一箇所に閉じ込めている」ことです。
プロジェクト全体で「空なら 0」「空なら -1」など、ルールを統一できます。
「最小の要素そのもの」を取得する(Comparator 利用)
例:最も安い商品オブジェクトを取得する
「最小値」ではなく、「最小値を持つオブジェクトそのもの」が欲しいことも多いです。
例えば、「最も安い商品」を取りたい場合。
import java.util.Comparator;
import java.util.List;
public class MinItemSample {
public static void main(String[] args) {
List<Item> items = List.of(
new Item("A", 100),
new Item("B", 250),
new Item("C", 80)
);
Item minItem = items.stream()
.min(Comparator.comparingInt(Item::getPrice))
.orElse(null); // 空なら null
System.out.println(minItem.getName()); // C
}
}
Javaここでの重要ポイントは二つです。
一つ目は、min(Comparator.comparingInt(Item::getPrice)) という一行が
「価格を基準に最小の要素を選ぶ」というルールを表していることです。
二つ目は、戻り値が Optional<Item> なので、orElse(null) や orElseThrow(...) で「空だったときの扱い」を決める必要があることです。
これもユーティリティにしてしまうと、呼び出し側が楽になります。
import java.util.Comparator;
import java.util.List;
public final class Mins {
private Mins() {}
public static <T> T minOrNull(List<T> source, Comparator<? super T> comparator) {
if (source == null || source.isEmpty()) {
return null;
}
return source.stream()
.min(comparator)
.orElse(null);
}
}
Java使い方はこうです。
Item minItem = Mins.minOrNull(items, Comparator.comparingInt(Item::getPrice));
Java「最小の値」ではなく「最小の要素」が欲しいときは、
このパターンを素直に使うと読みやすくなります。
null を含むデータの最小値取得
「null を無視する」か「null を最大扱いにする」か
現実のデータには null が混ざります。
最小値取得で大事なのは、「null をどう扱うか」を決めることです。
例えば、「null は無視して最小値を取る」なら、こう書きます。
public static Integer minIntIgnoreNull(List<Integer> source) {
if (source == null || source.isEmpty()) {
return null;
}
return source.stream()
.filter(v -> v != null)
.mapToInt(Integer::intValue)
.min()
.orElseThrow(); // null 以外が一つもなければ例外
}
Javaあるいは、「null は最大扱い(とても大きな値)にする」なら、mapToInt の前に変換してしまう方法もあります。
public static int minIntTreatNullAsMax(List<Integer> source) {
if (source == null || source.isEmpty()) {
return 0;
}
return source.stream()
.mapToInt(v -> v == null ? Integer.MAX_VALUE : v)
.min()
.orElse(0);
}
Javaここでの重要ポイントは、
「null の扱いも“最小値取得のルール”の一部」だと意識することです。
ユーティリティに閉じ込めておけば、
呼び出し側は「このメソッドは null をどう扱うのか」を意識せずに済みます。
最小値取得と「ビジネスルール」の結びつけ方
「最小日付」「最小バージョン」「最小ステータス」など
最小値取得は、単なる数値だけでなく、
日付やバージョン、ステータスなどにもよく使います。
例えば、「最も古い注文日」を取りたいなら、こうです。
import java.time.LocalDate;
import java.util.Comparator;
import java.util.List;
class Order {
private final String id;
private final LocalDate orderedAt;
public Order(String id, LocalDate orderedAt) {
this.id = id;
this.orderedAt = orderedAt;
}
public String getId() { return id; }
public LocalDate getOrderedAt() { return orderedAt; }
}
List<Order> orders = List.of(
new Order("A001", LocalDate.of(2024, 1, 10)),
new Order("A002", LocalDate.of(2024, 1, 5)),
new Order("A003", LocalDate.of(2024, 1, 20))
);
Order oldest =
Mins.minOrNull(orders, Comparator.comparing(Order::getOrderedAt));
Javaここでのポイントは、
「何を“最小”とみなすかはビジネスルールそのもの」だということです。
日付なら「一番古いもの」、
バージョンなら「一番低いもの」、
ステータスなら「優先度が一番低いもの」など、
Comparator と組み合わせることで、
“ビジネス上の最小”をそのままコードに表現できます。
まとめ:最小値取得ユーティリティで身につけてほしい感覚
最小値取得は、
単に「一番小さいものを探すテクニック」ではなく、
「空・null・オブジェクト・比較ルールを含めて、“最小”をどう定義するかをコードに刻む作業」です。
数値 List なら mapToInt(...).min().orElse(デフォルト) の形を基本として覚える。
オブジェクト一覧では、「どの項目を最小化するか」を関数(Item::getPrice など)で渡す汎用ユーティリティにする。
「最小値そのもの」だけでなく、「最小の要素そのもの」を min(Comparator...) で取得するパターンも押さえる。
null や空コレクションの扱い(0にする、nullを返す、例外にする)をユーティリティ側で統一する。
日付やステータスなど、「ビジネス上の最小」を Comparator で表現する感覚を持つ。
もしあなたのコードのどこかに、
毎回 for 文で最小値を手作業で探している箇所があるなら、
それを一度「最小値取得ユーティリティ+Stream」に置き換えられないか眺めてみてください。
その小さな整理が、
「“最小”という概念を、迷いなく安全に扱えるエンジニア」への、
確かな一歩になります。
