はじめに
現在、私が進行しているJavaの勉強会でまとめた内容です。
内容に不正確な点があれば、ご指摘いただけるとありがたいです。
- 韓国人として、日本語とコンピュータの勉強を同時に行うために、ここに文章を書いています
- 翻訳ツールの助けを借りて書いた文章なので、誤りがあるかもしれません
演算子
- 算術演算子
- ビット演算子
- 関係演算子
- 論理演算子
- instanceof
- 代入(=)演算子
- アロー(->)演算子
- 三項演算子
- 演算子の優先順位
- Java 13. switch演算子
Javaで提供される演算子
演算子と被演算子とは?
- 演算子: 演算に使用される記号(+, - など)
- 被演算子: 演算に使用される対象(1, 2, a など)
ほとんどの演算はプリミティブ型でのみ使用可能です。
- Stringクラスは除く
String str1 = "Hello, ";
String str2 = "World!";
String result = str1 + str2; // 文字列連結演算
System.out.println(result); // "Hello, World!"
- Wrapperクラスは除く(AutoBoxing)を通じてプリミティブ型に変換された後に計算される
Integer a = 10;
Integer b = 20;
int sum = a + b; // AutoBoxingを通じてプリミティブintに変換された後に演算
- instanceof演算子は除く
演算子の種類
= > < ! ~ ? : ->
== >= <= != && || ++ --
+ - * / & | ^ % << >> >>>
+= -= *= /= &= |= ^= %= <<= >>= >>>=
算術演算子
算術演算子 | 説明 |
---|---|
+ | 加算(文字列の連結にも使用される) |
- | 減算 |
* | 乗算 |
/ | 除算 |
% | 剰余 |
class ArithmeticDemo {
public static void main (String[] args) {
int result = 1 + 2;
// result is now 3
System.out.println("1 + 2 = " + result);
int original_result = result;
result = result - 1;
// result is now 2
System.out.println(original_result + " - 1 = " + result);
original_result = result;
result = result * 2;
// result is now 4
System.out.println(original_result + " * 2 = " + result);
original_result = result;
result = result / 2;
// result is now 2
System.out.println(original_result + " / 2 = " + result);
original_result = result;
result = result + 8;
// result is now 10
System.out.println(original_result + " + 8 = " + result);
original_result = result;
result = result % 7;
// result is now 3
System.out.println(original_result + " % 7 = " + result);
}
}
- 결과
1 + 2 = 3
3 - 1 = 2
2 * 2 = 4
4 / 2 = 2
2 + 8 = 10
10 % 7 = 3
-
割り算演算子
/
と剰余演算%
は、オペランドが整数のときに0で割ることはできず、ArithmeticException
エラーが発生します -
整数型の割り算 (
/
) で 0で割る場合、ArithmeticException
が発生します。一方で、浮動小数点数の場合は例外が発生せず、Infinity または NaN の値が返されます
Stringの演算もUnicodeで可能です
// Stringと他の型の+演算
int number = 42;
String result = "Number: " + number; // 他の型も自動的にStringに変換
String str = "a";
System.out.println(str + 2); // "a2" 出力
System.out.println("a" + 2); // "a2" 出力
char c = 'a';
System.out.println((char)(c + 2)); // 'c' 出力
// 'a'(97) + 2 = 99('c')
// Stringに変換したい場合
String result = String.valueOf((char)(c + 2)); // "c"
単項演算子
単項演算子 | 説明 |
---|---|
+ | 正数を表す(省略可能だが、明示可能) |
- | 負数を表す |
++ | 1増加 |
-- | 1減少 |
! | 反対(論理否定演算子) |
class UnaryDemo {
public static void main(String[] args) {
int result = +1;
// result is now 1
System.out.println(result);
result--;
// result is now 0
System.out.println(result);
result++;
// result is now 1
System.out.println(result);
result = -result;
// result is now -1
System.out.println(result);
boolean success = false;
// false
System.out.println(success);
// true
System.out.println(!success);
}
}
増加/減少演算子は被演算子の前後でも適用が可能です。
class PrePostDemo {
public static void main(String[] args){
int i = 3;
i++;
// prints 4
System.out.println(i);
++i;
// prints 5
System.out.println(i);
// prints 6
System.out.println(++i);
// prints 6
System.out.println(i++);
// prints 7
System.out.println(i);
}
}
int a = -10;
System.out.println(-x); // 10を出力
比較演算子(等価、関係演算子)
オブジェクトのアドレスを比較します。(参照型でも同様です)
比較演算子 | 説明 |
---|---|
== | 2つの値が同じときに真 |
!= | 2つの値が異なるときに真 |
> | 最初の値が2番目の値より大きいときに真 |
>= | 最初の値が2番目の値以上のときに真 |
< | 最初の値が2番目の値より小さいときに真 |
<= | 最初の値が2番目の値以下のときに真 |
class ComparisonDemo {
public static void main(String[] args){
int value1 = 1;
int value2 = 2;
if(value1 == value2)
System.out.println("value1 == value2");
if(value1 != value2)
System.out.println("value1 != value2");
if(value1 > value2)
System.out.println("value1 > value2");
if(value1 < value2)
System.out.println("value1 < value2");
if(value1 <= value2)
System.out.println("value1 <= value2");
}
}
- 결과
value1 != value2
value1 < value2
value1 <= value2
int a = 5
a ++ == -- a // true
論理演算子
2つ以上のboolean表現式を評価して結果を生成する演算子
条件演算子 | 説明 |
---|---|
&& | (AND) 両方の条件が真のときのみ結果が真 |
|| | (OR) どちらか一方の条件が真であれば結果が真 |
?: | 三項演算子 条件 ? 真の場合の値 : 偽の場合の値 |
- 左側がfalseの場合、右側は評価されません
// aがfalseの場合、bは評価されません
if (a && b)
// aがtrueの場合、bは評価されません
if (a || b)
-
&
と|
は常に両側を評価します
// aがfalseでもbを評価します
if (a & b)
// aがtrueでもbを評価します
if (a | b)
-
||
、&&
とは異なり、必ず両辺の値を比較するため、パフォーマンス上&&
、||
の方が有利です
三項演算子
result = (condition) ? expression1 : expression2;
-
condition
: 評価する条件(trueまたはfalseに評価される式) -
expression1
:condition
がtrue
のときに実行される式 -
expression2
:condition
がfalse
のときに実行される式
条件 ? 真のときの値 : 偽のときの値
以下のような形式で使用することもできますが、演算は効率的ではありません。
なぜなら、必ず右側の値までチェックする必要があるからです。
int score = 85;
String grade = (score >= 90) ? "A" :
(score >= 80) ? "B" :
(score >= 70) ? "C" :
(score >= 60) ? "D" : "F";
- メソッドの実行結果を条件として使用することもできます
String name = user != null ? user.getName() : "Unknown";
// someMethodの結果がtrueの場合に実行される処理
boolean hasPermission = isAdmin() ? true : checkPermission(user);
ビット演算子
演算子 | 説明 |
---|---|
& | 両方のビットが1のときのみ1 (AND) |
| | どちらかのビットが1であれば1 (OR) |
^ | ビットが異なるとき1 (XOR) |
~ | ビット値を反転 (NOT) |
<< | 左にビットを移動 (LEFT SHIFT) |
>> | 右にビットを移動 (RIGHT SHIFT) |
>>> | 右にビットを移動(0で埋める) |
// & (AND 演算)
5 の表現: 00000000 00000000 00000000 00000101
3 の表現: 00000000 00000000 00000000 00000011
5 & 3: 00000000 00000000 00000000 00000001 // 結果: 1(両方が1のビットのみ1)
// | (OR 演算)
5 の表現: 00000000 00000000 00000000 00000101
3 の表現: 00000000 00000000 00000000 00000011
5 | 3: 00000000 00000000 00000000 00000111 // 結果: 7(どちらかが1なら1)
// ^ (XOR 演算)
5 の表現: 00000000 00000000 00000000 00000101
3 の表現: 00000000 00000000 00000000 00000011
5 ^ 3: 00000000 00000000 00000000 00000110 // 結果: 6(異なるビットは1)
// << (左シフト)
5 の表現: 00000000 00000000 00000000 00000101
5 << 1: 00000000 00000000 00000000 00001010 // 結果: 10(左に1ビットシフト、右は0)
// >> (符号付き右シフト)
-8 の表現: 11111111 11111111 11111111 11111000
-8 >> 1: 11111111 11111111 11111111 11111100 // 結果: -4(符号ビット1を維持)
// >>> (符号なし右シフト)
-8 の表現: 11111111 11111111 11111111 11111000
-8 >>> 1: 01111111 11111111 11111111 11111100 // 結果: 2147483644(必ず0で埋める)
- ビット演算は、2進数に基づいてメモリや演算速度の面で利点をもたらします
instanceof 演算子
- オブジェクトが指定された型と一致するかを確認する(オブジェクトの型を確認する演算子)
- instanceofを使用する際、nullはクラスや型ではないため、常にfalseと判断されます
- プリミティブ型は演算できません
String str = null;
System.out.println(str instanceof String); // false
int number = 42;
if (number instanceof Integer) { } // コンパイルエラー
class InstanceofDemo {
public static void main(String[] args) {
Parent obj1 = new Parent();
Parent obj2 = new Child();
System.out.println("obj1 instanceof Parent: "
+ (obj1 instanceof Parent));
System.out.println("obj1 instanceof Child: "
+ (obj1 instanceof Child));
System.out.println("obj1 instanceof MyInterface: "
+ (obj1 instanceof MyInterface));
System.out.println("obj2 instanceof Parent: "
+ (obj2 instanceof Parent));
System.out.println("obj2 instanceof Child: "
+ (obj2 instanceof Child));
System.out.println("obj2 instanceof MyInterface: "
+ (obj2 instanceof MyInterface));
}
}
class Parent {}
class Child extends Parent implements MyInterface {}
interface MyInterface {}
obj1 instanceof Parent: true
obj1 instanceof Child: false
obj1 instanceof MyInterface: false
obj2 instanceof Parent: true
obj2 instanceof Child: true
obj2 instanceof MyInterface: true
アロー(->)演算子
- アロー(->)演算子(ラムダ式)はJava 8で導入
- 関数型プログラミングを表現
- 副作用(side-effect)の発生を最小限に抑えるため
// Bad: 副作用があるコード
int sum = 0;
list.forEach(num -> {
sum += num; // 外部変数を変更(副作用)
});
// Good: 副作用のないコード
int sum = list.stream()
.reduce(0, (a, b) -> a + b); // 外部変数の変更なし
```java
// アロー演算子(->)を使用したラムダ式のさまざまな形
(引数) -> { 実行文; } // 基本形
() -> System.out.println("Hello") // 引数なし
x -> x * x // 引数が1つのときは括弧省略可能
(a, b) -> a + b // 引数が複数
その他の条件や使用法については、ラムダ式の別セクションで取り扱います。
代入演算子
=
+=
-=
*=
/=
%=
&=
^=
|=
<<=
>>=
>>>=
- 右側の値を左側の被演算子に割り当てます
int a = 0;
long b = 1L;
double c = 0.4;
Point point1 = new Point(23, 94);
Point point2 = point1;
point2.x = 50;
System.out.println(point1.x); // 出力: 50
System.out.println(point1 == point2); // true
int a = b = c = d;
- 右から左に値が反映されます
- 上記の式では、
d
の値が反映されます
int x = 5;
x += x++; // 11
int x = 5;
x += ++x; // x = 12
演算子のまとめ
単純代入演算子
-
=
: 単純代入演算子
算術演算子
-
+
: 加算演算子(文字列の連結にも使用) -
-
: 減算演算子 -
*
: 乗算演算子 -
/
: 除算演算子 -
%
: 剰余演算子
単項演算子
-
+
: 正数符号演算子(通常、数値はこの符号なしでも正数) -
-
: 負数符号演算子;式を負数にする -
++
: インクリメント演算子;値を1増加させる -
--
: デクリメント演算子;値を1減少させる -
!
: 論理否定演算子;boolean値を反転させる
等価および関係演算子
-
==
: 等しい -
!=
: 等しくない -
>
: より大きい -
>=
: 以上 -
<
: より小さい -
<=
: 以下
条件演算子
-
&&
: 条件付きAND(論理積) -
||
: 条件付きOR(論理和) -
?:
: 三項演算子(if-then-elseの省略形)
型比較演算子
-
instanceof
: オブジェクトを特定の型と比較する
ビットおよびビットシフト演算子
-
~
: 単項ビット反転 -
<<
: 符号付き左シフト -
>>
: 符号付き右シフト -
>>>
: 符号なし右シフト -
&
: ビットAND -
^
: ビット排他的OR(XOR) -
|
: ビット包含OR
演算子の優先順位
優先順位 | 演算子の種類 | 演算子 | 方向 |
---|---|---|---|
1 | 後置演算子 | expr++, expr-- | →(左から右) |
2 | 単項演算子 | ++expr, --expr, +expr, -expr, ~, ! | →(左から右) |
3 | 乗算/除算演算子 | *, /, % | →(左から右) |
4 | 加算/減算演算子 | +, - | →(左から右) |
5 | シフト演算子 | <<, >>, >>> | →(左から右) |
6 | 関係演算子 | <, >, <=, >=, instanceof | →(左から右) |
7 | 等価演算子 | ==, != | →(左から右) |
8 | ビット論理積 | & | →(左から右) |
9 | ビット排他的論理和 | ^ | →(左から右) |
10 | ビット論理和 | | | →(左から右) |
11 | 論理 AND | && | →(左から右) |
12 | 論理 OR | || | →(左から右) |
13 | 三項演算子 | ? : | →(左から右) |
14 | 代入演算子 | =, +=, -=, *=, /=, %=, &=, ^=, |= | ←(右から左) |
-
()
で囲むことで演算の順序を変更することができます
Java 13. switch演算子
従来のswitch文には以下の問題が発生します。
- break文を省略すると
フォールスルー(fall-through)
が発生する - 値を返すことができない
- 開発者がすべてのケースをチェックしたかをコンパイル時に確認できない
public class SwitchDemo {
public static void main(String[] args) {
int month = 8;
String monthString; // 外部に値を宣言
switch (month) {
// caseを省略する危険がある
case 1: monthString = "January";
break;
case 2: monthString = "February";
break;
case 3: monthString = "March";
break;
case 4: monthString = "April";
break; // breakを省略するとfall-through問題発生
// 以下すべての月が出力される
case 5: monthString = "May";
break;
case 6: monthString = "June";
break;
case 7: monthString = "July";
break;
case 8: monthString = "August";
break;
case 9: monthString = "September";
break;
case 10: monthString = "October";
break;
case 11: monthString = "November";
break;
case 12: monthString = "December";
break;
default: monthString = "Invalid month";
break;
}
System.out.println(monthString);
}
}
このように、switchでは->
演算子を使用でき、その利点は以下の通りです。
- より簡潔な構文を提供
- break文が不要
- fall-throughの危険がない(2番と関連し、returnがなくても自動で終了)
- 値を返すことが可能
- コンパイラがすべてのcaseが処理されているかを検査(完全性チェック)
-
yield
を使用してswitchの結果を返すこともできます
public class SwitchDemo {
public static void main(String[] args) {
int month = 8;
// 基本的なアロー演算子の使用
// 値を直接割り当て
// すべてのcaseが処理されていないとコンパイルエラーが発生
// break文が不要でfall-throughの危険がない
String monthString = switch (month) {
case 1 -> "January";
case 2 -> "February";
case 3 -> "March";
case 4 -> "April";
case 5 -> "May";
case 6 -> "June";
case 7 -> "July";
case 8 -> "August";
case 9 -> "September";
case 10 -> "October";
case 11 -> "November";
case 12 -> "December";
default -> "Invalid month";
};
// 方法2: 複数のcaseをまとめて処理
String season = switch (month) {
case 12, 1, 2 -> "Winter";
case 3, 4, 5 -> "Spring";
case 6, 7, 8 -> "Summer";
case 9, 10, 11 -> "Fall";
default -> "Invalid month";
};
System.out.println(monthString);
System.out.println(season);
}
}
// 従来の方法: 外部変数が必要
String result; // 外部変数の宣言が必要
switch(value) {
case 1:
doSomething();
result = "ONE"; // 外部変数に代入
break;
}
// 新しい方法: 直接返す
String result = switch(value) { // 直接代入が可能
case 1 -> {
doSomething();
yield "ONE"; // 直接返却
}
};
リファレンス