タイトル: 論理演算子
SEOタイトル: Java 論理演算子完全ガイド (&&/||/!) - 短絡評価と非短絡の違い
| この記事の要点 |
|
3 つの基本論理演算子
| 演算子 | 名称 | 真理表 | 短絡 |
|---|---|---|---|
&& | 論理 AND | 両方 true で true | ★ する |
|| | 論理 OR | どちらか true で true | ★ する |
! | 論理 NOT | true ⇔ false 反転 | - |
& | ビット AND / 非短絡 AND | 同上 (boolean のとき) | しない |
| | ビット OR / 非短絡 OR | 同上 (boolean のとき) | しない |
^ | XOR | 異なる値で true | - |
boolean a = true;
boolean b = false;
a && b; // false
a || b; // true
!a; // false
// 値が等しいか
int x = 5;
(x > 0) && (x < 10); // true
(x < 0) || (x > 100); // false
// XOR (排他的論理和)
true ^ false; // true
true ^ true; // false
短絡評価 (Short-Circuit Evaluation)
&& は左辺が false なら右辺を評価しません。|| は左辺が true なら右辺を評価しません。これは性能だけでなくNullPointerException 回避の定石として使います。
// ★ 定石: null チェック + メソッド呼び出し
String s = getString(); // null かもしれない
// ❌ 危険: s が null だと NullPointerException
if (s.length() > 0 && s != null) { ... }
// ✅ 短絡で安全
if (s != null && s.length() > 0) {
// s != null が false なら s.length() は評価されない
System.out.println(s);
}
// OR 版
if (s == null || s.isEmpty()) {
System.out.println("空");
}
// 副作用に注意 (右辺が呼ばれないことがある)
int counter = 0;
boolean f() { counter++; return true; }
if (false && f()) { ... } // f() は呼ばれない → counter 増えない
if (true || f()) { ... } // f() は呼ばれない
非短絡演算子 (& / |)
boolean に対して & / | を使うと必ず両辺を評価します。副作用が必要な特殊ケースのみ:
// ❌ 普通は使わない
if (validateA() & validateB()) {
// 両方のバリデーション関数を必ず呼ぶ
// エラーを両方記録したいときなど
}
// 整数では純粋にビット演算
int flags = 0b1010;
int mask = 0b1100;
flags & mask; // 0b1000 = 8
flags | mask; // 0b1110 = 14
flags ^ mask; // 0b0110 = 6
~flags; // ビット反転
// シフト
flags << 2; // 0b101000 = 40
flags >> 1; // 0b101 = 5
flags >>> 1; // 符号なし右シフト
三項演算子 (Conditional Operator)
int age = 20;
String label = age >= 18 ? "成人" : "未成年";
// ネスト可能だが可読性が下がる
String grade = score >= 90 ? "A"
: score >= 80 ? "B"
: score >= 70 ? "C"
: "F";
// null 合体 (Java では Objects.requireNonNullElse)
String name = Objects.requireNonNullElse(input, "default");
// または
String name2 = (input != null) ? input : "default";
// Optional (Java 8+)
String s = Optional.ofNullable(input).orElse("default");
Java 14+ 式 switch (Switch Expression)
// 従来 switch (文)
String label;
switch (day) {
case MONDAY:
case TUESDAY:
label = "平日"; break;
case SATURDAY:
case SUNDAY:
label = "週末"; break;
default:
label = "?";
}
// Java 14+ 式 switch (値を返す、break 不要)
String label2 = switch (day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "平日";
case SATURDAY, SUNDAY -> "週末";
};
// 複雑な処理は yield
int v = switch (op) {
case "add" -> a + b;
case "sub" -> a - b;
default -> {
log("unknown op: " + op);
yield 0;
}
};
演算子優先順位
論理演算子の優先順位 (高 → 低):
!(NOT) - 単項*,/,%+,-<,>,<=,>=,instanceof==,!=&(ビット/論理 AND)^(XOR)|(ビット/論理 OR)&&||? :(三項)=,+=, ...
// && は || より優先順位が高い
a || b && c // a || (b && c) と同じ
(a || b) && c // 明示
// 比較 → 論理 の順
x > 0 && x < 10 // (x > 0) && (x < 10)
// ! の落とし穴
!a == b // (!a) == b
!(a == b) // 等値の否定
JavaScript との違い
| 項目 | Java | JavaScript |
|---|---|---|
&& の戻り値 | 必ず boolean | 最後に評価した値 (truthy/falsy) |
|| の戻り値 | 必ず boolean | 最後に評価した値 |
| truthy/falsy | 無し (boolean のみ) | あり (0, "", null, undefined は falsy) |
| null 合体 | Objects.requireNonNullElse | ?? |
// JavaScript では && / || は値を返す
"abc" || "default" // "abc"
null || "default" // "default"
0 && "x" // 0
1 && "x" // "x"
// JS のデフォルト値イディオム (古い)
const name = input || "default"; // input が "" だと "default" に!
// JS の正しい null 合体 (ES2020+)
const name = input ?? "default"; // null/undefined のときだけ
FAQ
Q: && と & の使い分けは?
A: 99% は &&。& は両辺の副作用が必要な特殊ケース or 整数ビット演算のとき。
Q: !flag == true と書いて警告された
A: !(flag == true) ではなく (!flag) == true と解釈されます。意図と違う可能性。素直に !flag や flag != true。
Q: 条件が複雑すぎて読みにくい
A: 意味のある変数に分解します。boolean isAdult = age >= 18; のように。