03_연산자

Tasker_Jang·2024년 2월 26일
0

03_연산자

1. 부호/증감 연산자

// +: 피연산자의 부호 유지
// -: 피연산자의 부호 변경

// 2. 부호를 변경하는 것도 연산
byte b = 100;
// 아래 코드는 컴파일 에러 발생
// byte, short, int 연산의 결과는 int 타입이어야 하므로
byte result = -b;

2. 선행증감과 후행증감

// 선행증감: ++,--를 먼저 수행
// 후행증감: ++,--를 나중에 수행 (다른 연산을 먼저 수행한다.)

int x = 1;
int y = 1;
int result1 = ++x + 10; // x를 1증가한 뒤 10을 더해준다.
int result2 = y++ + 10; // y에 10을 더한다. 이후 y값은 1에서 2로 바뀜
x++;
++x; // 단지 변수 단독으로 증감 연산 수행 => 앞 뒤 모두 결과가 동일하다.
int x = 10;
int z = x++; // z= 10, x= 11이 된다. 대입도 연산이기 때문이다.
int X = 10;
int z = ++x; // z와 x 값 모두 11이 된다. 증감식 먼저 수행한 뒤 대입을 수행하기 때문이다.

3. 산술 연산자

// +, -, *, /, %로 총 5개의 산술 연산자가 존재

// 5. 산술 연산의 특징
// byte, short, char, int의 연산은 결과가 항상 int 타입이다.
// but 그 중 하나가 long 타입이면 연산의 결과는 long이다.
// 피연산자 중 하나가 실수 타입이면 연산의 결과는 실수 타입이다.

// 예시 코드
public class ArithmeticOperations {
    public static void main(String[] args) {
        // byte, short, char, int의 연산은 결과가 항상 int 타입
        byte byteValue1 = 10;
        byte byteValue2 = 20;
        int result1 = byteValue1 + byteValue2; // 결과는 int 타입
        System.out.println("Result 1: " + result1);

        // 하나가 long 타입이면 결과는 long 타입
        int intValue = 30;
        long longValue = 40L;
        long result2 = intValue + longValue; // 결과는 long 타입
        System.out.println("Result 2: " + result2);

        // 피연산자 중 하나가 실수 타입이면 결과는 실수 타입
        float floatValue = 3.14f;
        int intValue2 = 5;
        float result3 = floatValue * intValue2; // 결과는 float 타입
        System.out.println("Result 3: " + result3);
    }
}

4. 오버플로우와 언더플로우

// 오버플로우: 타입이 허용하는 최대값을 벗어나는 것이다.
public class OverflowExample {
    public static void main(String[] args) {
        int maxValue = Integer.MAX_VALUE;
        int overflowedValue = maxValue + 1;

        System.out.println("Max Value: " + maxValue);
        System.out.println("Overflowed Value: " + overflowedValue); // 오버플로우 발생
    }
}

// 언더플로우: 타입이 허용하는 최소값을 벗어나는 것이다.
public class UnderflowExample {
    public static void main(String[] args) {
        int minValue = Integer.MIN_VALUE;
        int underflowedValue = minValue - 1;

        System.out.println("Min Value: " + minValue);
        System.out.println("Underflowed Value: " + underflowedValue); // 언더플로우 발생
    }
}

5. 각 변수별 저장 범위

public class DataTypeRanges {
    public static void main(String[] args) {
        // byte: 8-bit signed integer
        byte minValueByte = Byte.MIN_VALUE;  // -128
        byte maxValueByte = Byte.MAX_VALUE;  // 127
        System.out.println("byte Range: " + minValueByte + " to " + maxValueByte);

        // short: 16-bit signed integer
        short minValueShort = Short.MIN_VALUE;  // -32768
        short maxValueShort = Short.MAX_VALUE;  // 32767
        System.out.println("short Range: " + minValueShort + " to " + maxValueShort);

        // char: 16-bit unsigned integer (but often used to represent characters)
        char minValueChar = Character.MIN_VALUE;  // 0
        char maxValueChar = Character.MAX_VALUE;  // 65535 (unsigned)
        System.out.println("char Range: " + (int) minValueChar + " to " + (int) maxValueChar);

        // int: 32-bit signed integer
        int minValueInt = Integer.MIN_VALUE;  // -2147483648
        int maxValueInt = Integer.MAX_VALUE;  // 2147483647
        System.out.println("int Range: " + minValueInt + " to " + maxValueInt);

        // long: 64-bit signed integer
        long minValueLong = Long.MIN_VALUE;  // -9223372036854775808
        long maxValueLong = Long.MAX_VALUE;  // 9223372036854775807
        System.out.println("long Range: " + minValueLong + " to " + maxValueLong);

        // float: 32-bit single-precision floating-point
        float minValueFloat = Float.MIN_VALUE;  // 1.4E-45
        float maxValueFloat = Float.MAX_VALUE;  // 3.4028235E38
        System.out.println("float Range: " + minValueFloat + " to " + maxValueFloat);

        // double: 64-bit

 double-precision floating-point
        double minValueDouble = Double.MIN_VALUE;  // 4.9E-324
        double maxValueDouble = Double.MAX_VALUE;  // 1.7976931348623157E308
        System.out.println("double Range: " + minValueDouble + " to " + maxValueDouble);
    }
}

6. 부동 소수점 방식에서 일어나는 오차

public class FloatingPointError {
    public static void main(String[] args) {
        // 정확한 10진수 표현이 어려운 경우
        double result1 = 0.1 + 0.2;
        System.out.println("0.1 + 0.2 = " + result1); // 결과: 0.30000000000000004

        // 정확한 10진수 표현이 어려운 경우
        double result2 = 1.0 - 0.9;
        System.out.println("1.0 - 0.9 = " + result2); // 결과: 0.09999999999999998
    }
}

이 코드에서 0.1 + 0.21.0 - 0.9는 각각 예상과 다르게 결과가 나타납니다. 이는 부동 소수점 표현 방식에서 정확한 10진수 표현이 어렵기 때문에 발생하는 오차입니다.

=> 정확한 계산을 위해 정수 연산을 사용하자.

7. NaN와 Infinity의 처리

NaN 처리:

public class NaNExample {
    public static void main(String[] args) {
        double result1 = 0.0 / 0.0; // NaN (0으로 나누기)
        double result2 = Math.sqrt(-1.0); // NaN (음수의 제곱근)

        System.out.println("Result 1: " + result1); // NaN
        System.out.println("Result 2: " + result2); // NaN

        // NaN인지 확인
        if (Double.isNaN(result1)) {
            System.out.println("Result 1 is NaN");
        }

        // NaN을 특정 값으로 대체
        double replacementValue = 10.0;
        result1 = Double.isNaN(result1) ? replacementValue : result1;
        System.out.println("Result 1 (after replacement): " + result1); // 대체된 값
    }
}

Infinity 처리:

public class InfinityExample {
    public static void main(String[] args) {
        double positiveInfinity = 1.0 / 0.0; // 양의 무한대
        double negativeInfinity = -1.0 / 0.0; // 음의 무한대

        System.out.println("Positive Infinity: " + positiveInfinity); // Infinity
        System.out.println("Negative Infinity: " + negativeInfinity); // -Infinity

        // Infinity인지 확인
        if (Double.isInfinite(positiveInfinity)) {
            System.out.println("Positive Infinity");
        }

        // Infinity를 특정 값으로 대체
        double replacementValue = 100.0;
        positiveInfinity = Double.isInfinite(positiveInfinity) ? replacementValue : positiveInfinity;
        System.out.println("Positive Infinity (after replacement): " + positiveInfinity); // 대체된 값
    }
}

위 코드에서 Double.isNaN()은 NaN 여부를 확인하고, Double.isInfinite()는 Infinity 여부를 확인합니다. 이러한 메서드를 사용하여 특별한 값들을 처리하거나 대체할 수 있습니다.

8. 크기 비교와 동등 비교 연산자

크기 비교와 동등 비교 연산자는 자바에서 각각 <, >, <=, >=, ==, !=로 표현됩니다.

크기 비교 연산자 (<, >, <=, >=):

public class ComparisonOperators {
    public static void main(String[] args) {
        int a = 5;
        int b = 10;

        // 크기 비교 연산자 사용
        System.out.println("a < b: " + (a < b)); // true
        System.out.println("a > b: " + (a > b)); // false
        System.out.println("a <= b: " + (a <= b)); // true
        System.out.println("a >= b: " + (a >= b)); // false
    }
}

동등 비교 연산자 (==, !=):

public class EqualityOperators {
    public static void main(String[] args) {
        int x = 5;
        int y = 5;

        // 동등 비교 연산자 사용
        System.out.println("x == y: " + (x == y)); // true
        System.out.println("x != y: " + (x != y)); // false

        String str1 = "Hello";
        String str2 = "World";

        // 문자열의 동등 비교
        System.out.println("str1.equals(str2): " + str1.equals(str2)); // false
    }
}

위 코드에서는 크기 비교 연산자와 동등 비교 연산자를 각각의 상황에 맞게 사용한 예시입니다. 크기 비교 연산자는 숫자 비교에 사용되며, 동등 비교 연산자는 값이 같은지 여부를 판단하는 데 사용됩니다. 문자열의 경우에는 equals 메서드를 사용하여 동등 비교를 수행합니다.

9. 논리연산자

자바에서는 논리 연산자를 사용하여 논리적인 조건을 다양하게 조합할 수 있습니다. 주요 논리 연산자로는 && (논리 AND), || (논리 OR), ! (논리 NOT)이 있습니다.

논리 AND (&&):

public class LogicalAndOperator {
    public static void main(String[] args) {
        int age = 25;
        boolean isStudent = true;

        // 논리 AND 연산자 사용
        boolean result = (age > 18) && isStudent;

        System.out.println("Result: " + result); // true
    }
}

논리 OR (||):

public class LogicalOrOperator {
    public static void main(String[] args) {
        int temperature = 25;
        boolean isSunny = false;

        // 논리 OR 연산자 사용
        boolean result = (temperature > 30) || isSunny;

       

 System.out.println("Result: " + result); // false
    }
}

논리 NOT (!):

public class LogicalNotOperator {
    public static void main(String[] args) {
        boolean isRaining = true;

        // 논리 NOT 연산자 사용
        boolean result = !isRaining;

        System.out.println("Result: " + result); // false
    }
}

위의 코드에서는 논리 AND, OR, NOT 연산자를 사용하여 각각의 조건을 평가하고 결과를 출력하고 있습니다. 논리 연산자는 조건문, 반복문 등 다양한 상황에서 사용되어 프로그램의 흐름을 제어하는 데 유용합니다.

배타적 논리합 (^):

public class LogicalXorOperator {
    public static void main(String[] args) {
        boolean condition1 = true;
        boolean condition2 = false;

        // 배타적 논리합 연산자 사용
        boolean result = condition1 ^ condition2;

        System.out.println("Result: " + result); // true
    }
}

이 코드에서 ^ 연산자는 두 피연산자 중 하나만 참일 때 결과가 참이 되도록 동작합니다. 위 예시에서는 condition1이 참이고 condition2가 거짓이므로 결과는 참(true)이 됩니다.

10. 비트 논리 연산자

비트 논리 연산자는 비트 단위로 연산을 수행하는 연산자로서 & (AND), | (OR), ^ (XOR), ~ (NOT) 등이 있습니다.

비트 AND (&):

public class BitwiseAndOperator {
    public static void main(String[] args) {
        int a = 5; // 이진수: 0101
        int b = 3; // 이진수: 0011

        // 비트 AND 연산자 사용
        int result = a & b;

        System.out.println("Result: " + result); // 1 (이진수: 0001)
    }
}

비트 OR (|):

public class BitwiseOrOperator {
    public static void main(String[] args) {
        int a = 5; // 이진수: 0101
        int b = 3; // 이진수: 0011

        // 비트 OR 연산자 사용
        int result = a | b;

        System.out.println("Result: " + result); // 7 (이진수: 0111)
    }
}

비트 XOR (^):

public class BitwiseXorOperator {
    public static void main(String[] args) {
        int a = 5; // 이진수: 0101
        int b = 3; // 이진수: 0011

        // 비트 XOR 연산자 사용
        int result = a ^ b;

        System.out.println("Result: " + result); // 6 (이진수: 0110)
    }
}

비트 NOT (~):

public class BitwiseNotOperator {
    public static void main(String[] args) {
        int a = 5; // 이진수: 0101

        // 비트 NOT 연산자 사용
        int result = ~a;

        System.out.println("Result: " + result); // -6 (이진수: 11111111111111111111111111111010)
    }
}

비트 논리 연산자는 정수형 데이터 타입에서 각 비트를 처리하는 데 사용되며, 주로 저수준 프로그래밍이나 비트 조작이 필요한 상황에서 활용됩니다.

11. 비트 이동 연산자

비트 이동 연산자는 비트 단위로 특정 방향으로 비트를 이동시키는 연산자로서, 자바에서는 << (왼쪽 시프트), >> (오른쪽 시프트), >>> (부호 없는 오른쪽 시프트)가 있습니다.

왼쪽 시프트 (<<):

public class LeftShiftOperator {
    public static void main(String[] args) {
        int num = 5; // 이진수: 0000 0101

        // 왼쪽 시프트 연산자 사용
        int result = num << 2;

        System.out.println("Result: " + result); // 20 (이진수: 0001 0100)
    }
}

오른쪽 시프트 (>>):

public class RightShiftOperator {
    public static void main(String[] args) {
        int num = 16; // 이진수: 0001 0000

        // 오른쪽 시프트 연산자 사용
        int result = num >> 2;

        System.out.println("Result: " + result); // 4 (이진수: 0000 0100)
    }
}

부호 없는 오른쪽 시프트 (>>>):

public class UnsignedRightShiftOperator {
    public static void main(String[] args) {
        int num = -8; // 이진수: 1111 1000

        // 부호 없는 오른쪽 시프트 연산자 사용
        int result = num >>> 2;

        System.out.println("Result: " + result); // 1073741822 (이진수: 0011 1111 1111 1111 1111 1111 1111 1110)
    }
}

비트 이동 연산자는 주로 특정 비트 패턴을 원하는 방향으로 이동시키거나, 연산을 최적화하는 데 사용됩니다.

12. 복합 대입 연산자

자바에서 제공하는 11가지 복합 대입 연산자들은 다음과 같습니다:

  1. += (덧셈 후 대입): num1 += num2; // num1 = num1 + num2;
  2. -= (뺄셈 후 대입): num1 -= num2; // num1 = num1 - num2;
  3. *= (곱셈 후 대입): num1 *= num2; // num1 = num1 * num2;
  4. /= (나눗셈 후 대입): num1 /= num2; // num1 = num1 / num2;
  5. %= (나머지 연산 후 대입): num1 %= num2; // num1 = num1 % num2;
  6. &= (비트 AND 후 대입): num1 &= num2; // num1 = num1 & num2;
  7. |= (비트 OR 후 대입): num1 |= num2; // num1 = num1 | num2;
  8. ^= (비트 XOR 후 대입): num1 ^= num2; // num1 = num1 ^ num2;
  9. <<= (왼쪽 시프트 후 대입): num1 <<= num2; // num1 = num1 << num2;
  10. >>= (오른쪽 시프트 후 대입): num1 >>= num2; // num1 = num1 >> num2;
  11. >>>= (부호 없는 오른쪽 시프트 후 대입): num1 >>>= num2; // num1 = num1 >>> num2;

13. 삼항연산자

public class TernaryOperator {
    public static void main(String[] args) {
        int num1 = 5;
        int num2 = 10;

        // 삼항 연산자 사용
        int result = (num1 > num2) ? num1 : num2;

        System.out.println("Result: " + result); // 10
    }
}

14. 연산의 방향과 우선순위

자바에서 연산자는 특정 방향과 우선순위를 가지고 있습니다. 이러한 규칙을 따라 표현식이 계산되며, 연산자 우선순위에 따라 어떤 연산이 먼저 수행되는지 결정됩니다.

연산자의 방향:
1. 단항 연산자 방향: 단항 연산자(++, --, ! 등)는 피연산자의 왼쪽에 위치합니다.
2. 이항 연산자 방향: 대부분의 이항 연산자(+, -, *, / 등)는 좌측에서 우측으로 피연산자를 취합니다.

연산자의 우선순위:
1. Postfix(후위) 및 Prefix(전위) 연산자: ++, --
2. Multiplicative(곱셈, 나눗셈, 나머지) 연산자: , /, %
3. Additive(덧셈, 뺄셈) 연산자: +, -
4. Shift(시프트) 연산자: <<, >>, >>>
5. Relational(관계) 연산자: <, >, <=, >=, instanceof
6. Equality(동등) 연산자: ==, !=
7. Bitwise AND: &
8. Bitwise XOR: ^
9. Bitwise OR: |
10. Logical AND: &&
11. Logical OR: ||
12. Conditional(삼항) 연산자: ?:
13. Assignment(할당) 및 Compound Assignment(복합 할당) 연산자: =, +=, -=,
=, /=, %=, &=, ^=, |=, <<=, >>=, >>>=
14. 증가 및 감소 연산자: ++, --

이러한 우선순위와 방향을 이용하여 표현식의 계산 순서를 이해할 수 있습니다. 필요에 따라 괄호를 사용하여 우선순위를 변경할 수도 있습니다.

profile
터널을 지나고 있을 뿐, 길은 여전히 열려 있다.

0개의 댓글