演算子(Java)
変数や値を計算・比較・判定するための記号が演算子です。『Java』の演算子は種類が多いですが、日常的によく使う算術・比較・論理演算子を押さえておけば大半のコードを読み書きできます。整数除算の切り捨て挙動、文字列連結に使える + の特殊性、短絡評価の仕組みも合わせて解説します。
算術演算子
| 演算子 | 意味 | 例 | 結果 |
|---|---|---|---|
+ | 加算(文字列連結にも使用) | cursedEnergy + 100 | cursedEnergy の値 + 100 |
- | 減算 | hp - damage | hp の値 - damage の値 |
* | 乗算 | power * 2 | power の値 × 2 |
/ | 除算(整数÷整数は小数を切り捨て) | 7 / 2 | 3(小数点以下切り捨て) |
% | 剰余(割り算の余り) | 7 % 2 | 1 |
++ | インクリメント(1加算) | level++ | level の値に 1 を加算 |
-- | デクリメント(1減算) | level-- | level の値から 1 を減算 |
比較演算子
| 演算子 | 意味 | 例 |
|---|---|---|
== | 等しい(プリミティブ型の値比較・参照型は参照の同一性) | grade == 1 |
!= | 等しくない | status != "呪霊" |
> | より大きい | cursedEnergy > 9000 |
>= | 以上 | cursedEnergy >= 9000 |
< | より小さい | hp < 0 |
<= | 以下 | hp <= 0 |
論理演算子と短絡評価
| 演算子 | 意味 | 説明 |
|---|---|---|
&& | 論理AND(かつ) | 左辺が false なら右辺は評価しません(短絡評価)。両辺が true のとき true。 |
|| | 論理OR(または) | 左辺が true なら右辺は評価しません(短絡評価)。どちらかが true のとき true。 |
! | 論理NOT(否定) | true を false に、false を true に反転します。 |
短絡評価(short-circuit evaluation)とは、左辺の評価結果だけで全体の結果が確定する場合に右辺の評価を省略する仕組みです。&& は左辺が false の時点で結果が false に確定するため右辺を評価しません。|| は左辺が true の時点で結果が true に確定するため右辺を評価しません。null チェックをメソッド呼び出しの前に置く、などの用途に活用できます。
サンプルコード
ArithmeticDemo.java
public class ArithmeticDemo {
public static void main(String[] args) {
// --- 基本的な算術演算子 ---
int cursedEnergy = 300000; // 虎杖悠仁の呪力量です
int boost = 50000; // 黒閃によるブースト量です
System.out.println("加算: " + (cursedEnergy + boost)); // 350000
System.out.println("減算: " + (cursedEnergy - boost)); // 250000
System.out.println("乗算: " + (cursedEnergy * 2)); // 600000
System.out.println("除算: " + (cursedEnergy / boost)); // 6(小数切り捨て)
System.out.println("剰余: " + (cursedEnergy % boost)); // 0
// --- 整数除算の注意点 ---
// int 同士で割ると小数点以下は切り捨てられます
int totalFloors = 10;
int clearedFloors = 3;
int intResult = totalFloors / clearedFloors; // 3(小数切り捨て)
// double にキャストしてから割ると正確な小数値が得られます
double doubleResult = (double) totalFloors / clearedFloors; // 3.3333...
System.out.println("int除算(切り捨て): " + intResult); // 3
System.out.println("double除算(正確): " + doubleResult); // 3.3333333333333335
// --- インクリメント・デクリメント ---
int grade = 1; // 学年です
grade++; // 1加算します(grade = 2)
System.out.println("進級後の学年: " + grade); // 2
grade--; // 1減算します(grade = 1)
System.out.println("留年後の学年: " + grade); // 1
// --- 前置・後置の違い ---
// 後置(grade++): 現在の値を使った後にインクリメントします
// 前置(++grade): インクリメントしてから値を使います
int kills = 5;
System.out.println("後置: " + kills++); // 5(出力してから加算)
System.out.println("加算後: " + kills); // 6
int kills2 = 5;
System.out.println("前置: " + ++kills2); // 6(加算してから出力)
System.out.println("加算後: " + kills2); // 6
}
}
javac ArithmeticDemo.java java ArithmeticDemo 加算: 350000 減算: 250000 乗算: 600000 除算: 6 剰余: 0 int除算(切り捨て): 3 double除算(正確): 3.3333333333333335 進級後の学年: 2 留年後の学年: 1 後置: 5 加算後: 6 前置: 6 加算後: 6
StringConcatDemo.java
public class StringConcatDemo {
public static void main(String[] args) {
// --- 文字列連結に使う + ---
// String に + を使うと文字列連結になります
String name = "五条悟";
String title = "特級術師";
String result = name + "(" + title + ")";
System.out.println(result); // 五条悟(特級術師)
// --- 数値と文字列を + でつなぐと文字列連結になる ---
// 左から順に評価されるため、並び順に注意が必要です
int grade = 2;
int sectionNum = 5;
// 最初のオペランドが String なので全体が文字列連結になります
System.out.println("学年: " + grade + " 節: " + sectionNum); // 学年: 2 節: 5
// 括弧をつけると先に数値計算してから連結できます
System.out.println("合計: " + (grade + sectionNum)); // 合計: 7
// 括弧なしで数値 + 数値 + 文字列の順だと先に加算されます
System.out.println(grade + sectionNum + " 章"); // 7 章(数値として加算)
// 文字列が先にある場合は全部連結になります
System.out.println("章: " + grade + sectionNum); // 章: 25(連結)
}
}
javac StringConcatDemo.java java StringConcatDemo 五条悟(特級術師) 学年: 2 節: 5 合計: 7 7 章 章: 25
ComparisonLogicalDemo.java
public class ComparisonLogicalDemo {
public static void main(String[] args) {
// 呪術廻戦の術師データです
String sorcererName = "乙骨憂太";
int cursedEnergy = 500000;
boolean isSpecialGrade = true;
// --- 比較演算子 ---
System.out.println("cursedEnergy == 500000 : " + (cursedEnergy == 500000)); // true
System.out.println("cursedEnergy != 300000 : " + (cursedEnergy != 300000)); // true
System.out.println("cursedEnergy >= 500000: " + (cursedEnergy >= 500000)); // true
System.out.println("cursedEnergy < 100000: " + (cursedEnergy < 100000)); // false
// --- 論理演算子 ---
// &&(AND): 両方が true のとき true になります
boolean isElite = cursedEnergy >= 400000 && isSpecialGrade;
System.out.println("精鋭術師か: " + isElite); // true
// ||(OR): どちらかが true のとき true になります
boolean isDanger = cursedEnergy >= 400000 || sorcererName.equals("五条悟");
System.out.println("危険レベルか: " + isDanger); // true
// !(NOT): true/false を反転します
boolean isNotSpecial = !isSpecialGrade;
System.out.println("特級でないか: " + isNotSpecial); // false
// --- 短絡評価(short-circuit evaluation)---
// && は左辺が false なら右辺を評価しません
// null チェックをメソッド呼び出しの前に置くことで NullPointerException を防げます
String domain = null; // 領域展開の名前(未展開なので null)
// domain が null のとき domain.length() を呼ぶと NullPointerException になります
// && の短絡評価により、左辺が false なら右辺(domain.length() > 0)は評価されません
if (domain != null && domain.length() > 0) {
System.out.println("領域名: " + domain);
} else {
System.out.println("領域は未展開です。"); // こちらが実行されます
}
// || の短絡評価の例です
// 左辺が true になった時点で右辺は評価されません
boolean hasWeapon = true;
boolean hasCursedTool = false;
// hasWeapon が true なので hasCursedTool の評価はスキップされます
if (hasWeapon || hasCursedTool) {
System.out.println(sorcererName + "は武装しています。"); // こちらが実行されます
}
}
}
javac ComparisonLogicalDemo.java java ComparisonLogicalDemo cursedEnergy == 500000 : true cursedEnergy != 300000 : true cursedEnergy >= 500000: true cursedEnergy < 100000: false 精鋭術師か: true 危険レベルか: true 特級でないか: false 領域は未展開です。 乙骨憂太は武装しています。
代入演算子と三項演算子
| 演算子 | 意味 | 例 | 等価な式 |
|---|---|---|---|
+= | 加算して代入 | hp += 100 | hp = hp + 100 |
-= | 減算して代入 | hp -= 50 | hp = hp - 50 |
*= | 乗算して代入 | power *= 2 | power = power * 2 |
/= | 除算して代入 | energy /= 3 | energy = energy / 3 |
%= | 剰余を代入 | energy %= 100 | energy = energy % 100 |
条件 ? A : B | 三項演算子:条件が真なら A、偽なら B | grade >= 90 ? "特級" : "一般" | — |
AssignTernaryDemo.java
public class AssignTernaryDemo {
public static void main(String[] args) {
// --- 代入演算子 ---
int cursedEnergy = 300000; // 虎杖悠仁の初期呪力量です
cursedEnergy += 50000; // 黒閃後のブースト(+= で加算代入)
System.out.println("黒閃後: " + cursedEnergy); // 350000
cursedEnergy -= 80000; // バトルでの消耗(-= で減算代入)
System.out.println("消耗後: " + cursedEnergy); // 270000
cursedEnergy *= 2; // 領域展開で2倍(*= で乗算代入)
System.out.println("領域展開後: " + cursedEnergy); // 540000
int remainder = cursedEnergy;
remainder %= 100000; // 10万単位の余り(%= で剰余代入)
System.out.println("余り: " + remainder); // 40000
// --- 三項演算子 ---
// 条件 ? 真のときの値 : 偽のときの値
int level = 85;
String grade = (level >= 90) ? "特級" : (level >= 70) ? "1級" : "2級以下";
System.out.println("等級: " + grade); // 1級
// voidメソッドの呼び出しには使えません(値が必要な式のみ)
// 変数への代入や return 文の中で使います
boolean isElite = (cursedEnergy >= 400000);
System.out.println("精鋭か: " + isElite); // false(540000 → *= 後の値ではなく最新の値を確認)
}
}
javac AssignTernaryDemo.java java AssignTernaryDemo 黒閃後: 350000 消耗後: 270000 領域展開後: 540000 余り: 40000 等級: 1級 精鋭か: true
ビット演算子
整数の各ビットを直接操作する演算子です。フラグ管理・暗号処理・低レベルな最適化で使われます。通常のアプリケーションコードでは使う機会は少ないですが、読めると便利です。
| 演算子 | 意味 | 例(10進) | 例(2進) |
|---|---|---|---|
& | ビットAND(両方 1 なら 1) | 6 & 3 → 2 | 0110 & 0011 → 0010 |
| | ビットOR(どちらか 1 なら 1) | 6 | 3 → 7 | 0110 | 0011 → 0111 |
^ | ビットXOR(異なれば 1) | 6 ^ 3 → 5 | 0110 ^ 0011 → 0101 |
~ | ビット反転(NOT) | ~6 → -7 | 全ビットを反転します。 |
<< | 左シフト(×2n と等価) | 6 << 1 → 12 | 0110 → 1100 |
>> | 右シフト(÷2n と等価、符号を維持) | 6 >> 1 → 3 | 0110 → 0011 |
>>> | 符号なし右シフト(符号ビットも0で埋める) | -1 >>> 28 → 15 | 最上位ビットを 0 で埋めます。 |
よくあるミス1: 整数除算の切り捨て
int 型同士の除算では小数点以下が切り捨てられます。パーセントや比率を計算するときに発生しやすいミスです。
IntDivNg.java
public class IntDivNg {
public static void main(String[] args) {
int total = 10;
int cleared = 3;
// int / int は小数点以下切り捨てになります
double rate = total / cleared; // 期待: 3.333... 実際: 3.0
System.out.println("クリア率: " + rate + "%"); // 3.0% と出力されます(意図しない結果)
}
}
javac IntDivNg.java java IntDivNg クリア率: 3.0%
どちらか一方を double にキャストしてから除算すると正確な小数値が得られます。
IntDivOk.java
public class IntDivOk {
public static void main(String[] args) {
int total = 10;
int cleared = 3;
// (double) でキャストしてから割ることで小数が得られます
double rate = (double) total / cleared;
System.out.println("クリア率: " + rate); // 3.3333333333333335
}
}
javac IntDivOk.java java IntDivOk クリア率: 3.3333333333333335
よくあるミス2: == で文字列・ラッパーオブジェクトを比較する
== はプリミティブ型の値比較に使います。String や Integer などのオブジェクトに == を使うと、値ではなく参照(メモリ上の場所)を比較するため、内容が同じでも false になることがあります。
EqualityNg.java
public class EqualityNg {
public static void main(String[] args) {
String name1 = new String("乙骨憂太");
String name2 = new String("乙骨憂太");
// == は参照を比較するため、内容が同じでも false になる場合があります
System.out.println(name1 == name2); // false(参照が異なる)
System.out.println(name1.equals(name2)); // true(内容が同じ)
}
}
javac EqualityNg.java java EqualityNg false true
よくあるミス3: 演算子の優先順位と文字列連結の混乱
式は左から評価されます。文字列と数値を + で混在させるとき、文字列が先に現れると以降の + は全て文字列連結になります。数値計算を先に行いたい場合は括弧で囲みます。
PriorityNg.java
public class PriorityNg {
public static void main(String[] args) {
int grade = 2;
int section = 5;
// 文字列が先にあると、以降の + は全て文字列連結になります
System.out.println("合計: " + grade + section); // 合計: 25(意図: 合計: 7)
}
}
javac PriorityNg.java java PriorityNg 合計: 25
数値計算を先に行いたい場合は括弧 () で囲みます。
PriorityOk.java
public class PriorityOk {
public static void main(String[] args) {
int grade = 2;
int section = 5;
// 括弧で先に数値計算してから文字列連結します
System.out.println("合計: " + (grade + section)); // 合計: 7
}
}
javac PriorityOk.java java PriorityOk 合計: 7
概要
算術演算子で最も注意すべき点は int 同士の除算(/)が小数点以下を切り捨てることです。例えば 7 / 2 の結果は 3.5 ではなく 3 になります。正確な小数が必要な場合は、少なくとも一方のオペランドを double にキャスト((double) a / b)してから計算します。
文字列連結に使う + は、オペランドのどちらかが String の場合に文字列連結として機能します。式は左から順に評価されるため、数値の計算を先に行いたい場合は括弧 () で囲む必要があります。ループ内で大量の文字列を連結する場合は、+ を繰り返すよりも StringBuilder.append() を使うほうが効率的です。
論理演算子 && と || は短絡評価を行います。&& は左辺が false なら右辺を評価しないため、obj != null && obj.method() のように null チェックを前に置くことで安全に記述できます。|| は左辺が true なら右辺を評価しません。条件分岐への応用については『if / else if / else』も参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。