1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Javaの演算子を勉強してみました

Last updated at Posted at 2024-11-02

はじめに

現在、私が進行している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 の値が返されます

  • image.png

image.png

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: conditiontrueのときに実行される式
  • expression2: conditionfalseのときに実行される式
 条件 ? 真のときの値 : 偽のときの値

以下のような形式で使用することもできますが、演算は効率的ではありません。
なぜなら、必ず右側の値までチェックする必要があるからです。

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文には以下の問題が発生します。

  1. break文を省略するとフォールスルー(fall-through)が発生する
  2. 値を返すことができない
  3. 開発者がすべてのケースをチェックしたかをコンパイル時に確認できない
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では->演算子を使用でき、その利点は以下の通りです。

  1. より簡潔な構文を提供
  2. break文が不要
  3. fall-throughの危険がない(2番と関連し、returnがなくても自動で終了)
  4. 値を返すことが可能
  5. コンパイラがすべてのcaseが処理されているかを検査(完全性チェック)
  6. 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";    // 直接返却
    }
};

リファレンス

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?