allMatch / anyMatch を一言でいうと
allMatch と anyMatch は、
「Stream の要素が“条件を満たしているかどうか”を、真偽値で答える終端操作」です。
allMatch は「全部そうか?」、anyMatch は「ひとつでもそうか?」を聞くメソッドです。
どちらも戻り値は boolean で、filter のように要素を流し続けるのではなく、「判定したら終わり」というタイプの処理になります。
共通点:Predicate を受け取る「条件チェック」の終端操作
シグネチャと役割
どちらも、Predicate<T>(T -> boolean な関数)を 1 つ受け取ります。
boolean allMatch(Predicate<? super T> predicate)
boolean anyMatch(Predicate<? super T> predicate)
JavaPredicate<T> は、
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
Javaという関数型インターフェースで、
「要素 1 つを受け取って true / false を返す“条件”」を表します。
つまり、
allMatch / anyMatch は、
「この条件(Predicate)に対して、Stream 全体として true か false か?」
を答えるメソッドです。
anyMatch:ひとつでも条件を満たせば true
基本イメージとシンプルな例
anyMatch は、
「1 つでも条件を満たす要素があれば true、1 つもなければ false」
を返します。
import java.util.List;
public class AnyMatchBasic {
public static void main(String[] args) {
List<Integer> nums = List.of(1, 3, 5, 8, 9);
boolean hasEven =
nums.stream()
.anyMatch(n -> n % 2 == 0);
System.out.println(hasEven); // true(8 が偶数だから)
}
}
Javaここでは、n -> n % 2 == 0 が「偶数かどうか」の条件です。8 が条件を満たすので、anyMatch は true を返します。
もしリストが List.of(1, 3, 5, 7, 9) なら、
偶数が 1 つもないので false になります。
「見つかったらすぐ終わる」短絡評価
anyMatch は、
「条件を満たす要素を見つけた時点で、残りは見ずに処理を打ち切る」
という動きをします。
これは「短絡評価」と呼ばれ、
if (a || b) が a が true なら b を評価しない
のと同じイメージです。
要素数が多いときでも、
「最初の方で条件を満たすものが見つかれば、残りを見ずに済む」
というのがパフォーマンス上のメリットになります。
allMatch:全部が条件を満たしていれば true
基本イメージとシンプルな例
allMatch は、
「すべての要素が条件を満たしていれば true、1 つでも満たさないものがあれば false」
を返します。
import java.util.List;
public class AllMatchBasic {
public static void main(String[] args) {
List<Integer> nums = List.of(2, 4, 6, 8);
boolean allEven =
nums.stream()
.allMatch(n -> n % 2 == 0);
System.out.println(allEven); // true(全部偶数)
}
}
Javaここでは、全要素が偶数なので true です。
もし List.of(2, 4, 5, 8) のように 1 つでも奇数が混ざっていれば、allMatch は false を返します。
こちらも「ダメなやつを見つけたらすぐ終わる」
allMatch も短絡評価をします。
「条件を満たさない要素を 1 つでも見つけたら、その時点で false を返し、残りは見ない」
という動きです。
これは、
if (a && b) が a が false なら b を評価しない
のと同じイメージです。
実用的な例:User のリストで考える
例1:全員が成人かどうかをチェックする(allMatch)
import java.util.List;
class User {
private final String name;
private final int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
int getAge() { return age; }
}
public class AllMatchUserExample {
public static void main(String[] args) {
List<User> users = List.of(
new User("Alice", 20),
new User("Bob", 25),
new User("Charlie", 19)
);
boolean allAdult =
users.stream()
.allMatch(u -> u.getAge() >= 18);
System.out.println(allAdult); // false(Charlie が 18 未満)
}
}
Javaここでは、
「全員が 18 歳以上か?」を allMatch でチェックしています。
1 人でも 18 未満がいれば false なので、
「全員が条件を満たしているか?」という問いにぴったりです。
例2:誰か 1 人でもアクティブユーザーがいるか(anyMatch)
class User {
private final String name;
private final boolean active;
User(String name, boolean active) {
this.name = name;
this.active = active;
}
boolean isActive() { return active; }
}
public class AnyMatchUserExample {
public static void main(String[] args) {
List<User> users = List.of(
new User("Alice", false),
new User("Bob", false),
new User("Charlie", true)
);
boolean hasActive =
users.stream()
.anyMatch(User::isActive);
System.out.println(hasActive); // true(Charlie が active)
}
}
Javaここでは、
「アクティブなユーザーが 1 人でもいるか?」を anyMatch でチェックしています。
「1 人でもいれば OK」という問いには、anyMatch が自然にハマります。
filter + findAny と anyMatch の違い
どちらも「1 件でもあるか?」を調べられる
実は、
stream.anyMatch(cond)
Javaと
stream.filter(cond).findAny().isPresent()
Javaは、意味としてはほぼ同じです。
ただし、設計としては次のように使い分けるとスッキリします。
「要素そのものが欲しい」なら filter + findAny / findFirst。
「要素があるかどうかだけ知りたい」なら anyMatch。
例えば、
boolean hasAdmin =
users.stream()
.anyMatch(User::isAdmin);
Javaの方が、
boolean hasAdmin =
users.stream()
.filter(User::isAdmin)
.findAny()
.isPresent();
Javaよりも、「何をしたいコードか」が一目で分かります。
allMatch / anyMatch と「空の Stream」
空のときの挙動はどうなるか
ここは少し引っかかりやすいポイントなので、意識しておくと安心です。
空の Stream に対して anyMatch を呼ぶと、結果は false です。
「1 つも要素がないので、条件を満たすものも 1 つもない」という意味です。
一方、空の Stream に対して allMatch を呼ぶと、結果は true になります。
これは一見不思議ですが、
「反例が 1 つも存在しないので、“すべてが条件を満たしている”とみなす」
という論理(空集合に対する全称命題)の考え方に基づいています。
初心者向けには、
「anyMatch は“1 つでもあれば true”だから、要素が 0 個なら false」
「allMatch は“全部そうなら true”で、“そうじゃないやつ”が 1 つもいなければ true」
と覚えておけば十分です。
設計の指針:allMatch / anyMatch をどう使うか
自分の中でのルールを持つ
実務で迷わないために、シンプルなルールを持っておくと楽です。
「全員が条件を満たしているか?」
「全部が OK か?」
→ allMatch
「誰か 1 人でも条件を満たしているか?」
「1 つでも OK があればいいか?」
→ anyMatch
そして、
「要素そのものが欲しいなら findFirst / findAny」
「真偽値だけ欲しいなら allMatch / anyMatch」
という切り分けを意識しておくと、
Stream の終端操作の選択がかなりスムーズになります。
まとめ:for 文からの書き換えイメージ
最後に、よくある for 文のパターンを、allMatch / anyMatch に書き換えてみます。
例えば、
boolean hasAdult(List<User> users) {
for (User u : users) {
if (u.getAge() >= 18) {
return true;
}
}
return false;
}
Javaこれはそのまま、
boolean hasAdult(List<User> users) {
return users.stream()
.anyMatch(u -> u.getAge() >= 18);
}
Javaにできます。
また、
boolean allActive(List<User> users) {
for (User u : users) {
if (!u.isActive()) {
return false;
}
}
return true;
}
Javaは、
boolean allActive(List<User> users) {
return users.stream()
.allMatch(User::isActive);
}
Javaと書けます。
