3주차 : 연산자

Joo·2023년 4월 7일

1. 연산자란 무엇인가?

  • 연산자
    • 하나 이상의 피연산자를 받아서 특정한 연산을 수행하고 결과를 반환하는 기호
  • 피연산자
    • 연산의 대상이 되는 값이나 변수이다.
    • 연산자와 피연산자를 조합한 것

ex) 3 + 5

  • 3, 5 → 피연산자
  • + → 연산자
  • 은 결과값을 생성함 ex) 3 + 5 = 8
  • 연산자에는 다양한 종류가 있으며, 각각의 의미와 우선순위가 다름

2. 산술 연산자

수학적인 계산을 수행하는 연산자이다.

  • 산술 연산자 종류
    • + (더하기)
    • - (빼기)
    • * (곱하기)
    • / (나누기)
    • % (나머지)
  • 정수형실수형 모두에 적용
  • ArithmeticException
    • 나누기나머지 연산자 사용 시 0으로 나누면 발생하는 예외
  • 우선순위
    • 곱하기, 나누기, 나머지 > 더하기, 빼기
    • 같은 우선순위의 연산자
      • 왼쪽 → 오른쪽

3. 비트 연산자

정수형의 각 비트에 대해 논리적인 연산을 수행하는 연산자이다.

  • 비트 연산자 종류
    • ~ (비트 반전)
    • & (비트 AND)
    • | (비트 OR)
    • ^ (비트 XOR)
    • << (왼쪽 시프트)
    • >> (오른쪽 시프트)
    • >>> (Unsigned 오른쪽 시프트)
  • ~ (비트 반전)
    • 단항 연산자
    • 피연산자의 모든 비트를 0은 1로, 1은 0으로 바꿈
    • ex) 0 : 00000000 ⇒ ~0 : 11111111
  • & (비트 AND)
    • 피연산자의 각 비트에 대해 논리곱을 수행
    • 두 비트가 모두 1일 때만 결과가 1이 됨
    • ex) 5 & 3
      • 0101 & 0011 ⇒ 0001
  • | (비트 OR)
    • 피연산자의 각 비트에 대해 논리합을 수행
    • 즉, 두 비트 중 하나라도 1이면 결과가 1이 됨
    • ex) 5 | 3
      • 0101 | 0011 ⇒ 0111
  • ^ (비트 XOR)
    • 피연산자의 각 비트에 대해 배타적 논리합을 수행
    • 두 비트가 다를 때만 결과가 1이 됨
    • ex) 5 ^ 3
      • 0101 ^ 0011 ⇒ 0110
  • << (왼쪽 시프트)
    • 피연산자의 모든 비트를 왼쪽으로 주어진 수만큼 이동
    • 오른쪽에는 0으로 채운다.
    • ex)
      (byte) -128 : 10000000 ⇒ -128 << 2 : 00000000 = 0
    • x << n ⇒ x * 2^n
      ex) 2 << 3
      • 10 → 10000 = 16 = 2 * 2^3 = 2^4
  • >> (오른쪽 시프트)
    • 피연산자의 모든 비트를 오른쪽으로 주어진 수만큼 이동
    • 왼쪽에는 부호비트와 동일한 값으로 채운다.
    • ex)
      (byte) -128 : 10000000 ⇒ -128 >> 2 : 11100000 = -32
    • x >> n ⇒ x * 2^(-n)
      ex) 8 >> 2
      • 1000 → 10 = 2 = 8 * 2^(-2)
  • >>> (Unsigned 오른쪽 시프트)
    • 피연산자의 모든 비트를 오른쪽으로 주어진 수만큼 이동시킨다.
    • 왼쪽에는 항상 0으로 채운다.
    • ex)
      (byte) -128 : 10000000 ⇒ -128 >>> 2 : 00100000 = 32

4. 관계 연산자

피연산자의 크기나 순서를 비교하는 연산자이다.

  • 관계 연산자 종류
    • == (같음)
    • != (다름)
    • > (크다)
    • >= (크거나 같다)
    • < (작다)
    • <= (작거나 같다)
  • 정수형과 실수형 모두에 적용할 수 있음
    • 실수형의 경우 부동 소수점 방식으로 저장되기 때문에 오차가 발생할 수 있음
      public class FloatingPoint {
      
          public static void main(String[] args) {
              double a = 0.1;
              double b = 0.2;
      
              System.out.println((a + b) == 0.3);
          }
      }
      false
    • 정확한 계산이 필요한 경우 BigDecimal을 사용해서 계산해야 함
  • boolean 타입 리턴

5. 논리 연산자

피연산자의 참거짓을 판단하는 연산자이다.

  • 논리 연산자 종류
    • ! (논리부정)
    • && (논리곱)
    • || (논리합)
  • boolean 타입의 값이나 식에 적용할 수 있음
  • ! 논리부정
    • 피연산자의 참거짓을 반대로 바꿈
    • ex) !true ⇒ false
  • && 논리곱
    • 피연산자가 모두 참일 때만 결과가 참
  • || 논리합
    • 피연산자 중 하나라도 참이면 결과가 참
  • 단락평가
    • 왼쪽 피연산자의 결과에 따라 오른쪽 피연산자를 평가하지 않음
    • ex) false && true ⇒ 오른쪽은 보지도 않고 false
    • ex) true || false ⇒ 오른쪽은 보지도 않고 true

6. instanceof 연산자

객체가 특정 클래스의 인스턴스인지,
또는 특정 인터페이스를 구현한 클래스의 인스턴스인지 확인하는 연산자이다.

  • RTTI (Run Time Type Identification)
    • 실행 시간에 객체의 타입을 확인하는 기능
    • 자바에서는 instanceof 연산자를 통해 RTTI를 지원함
  • 객체의 프로토타입 체인
    • 객체가 상속받은 부모 객체들의 연결된 구조
    • 이를 통해 오른쪽에 작성한 클래스나 인터페이스의 prototype 속성이 있는지 검사함
  • 다형성을 지원함
    • 객체가 상위 클래스나 구현한 인터페이스의 인스턴스로도 간주됨
  • ex
    // Cat 클래스 인스턴스 생성
    Cat cat = new Cat("Kitty", "White");
    
    // instanceof 연산자를 사용하여 인스턴스의 클래스 확인
    System.out.println(cat instanceof Cat); // true
    System.out.println(cat instanceof Animal); // true
    System.out.println(cat instanceof Object); // true

7. 할당 연산자

오른쪽의 값을 왼쪽의 변수에 저장하는 연산자이다.

  • 할당 연산자 종류
    • = (기본 할당)
    • += (덧셈 후 할당)
    • -= (뺄셈 후 할당)
    • *= (곱셈 후 할당)
    • /= (나눗셈 후 할당)
    • %= (나머지 후 할당)
    • <<= (왼쪽 시프트 후 할당)
    • >>= (오른쪽 시프트 후 할당)
    • >>>= (부호 없는 오른쪽 시프트 후 할당)
    • &= (비트 AND 후 할당)
    • |= (비트 OR 후 할당)
    • ^= (비트 XOR 후 할당)
  • 기본 할당 연산자
    • 오른쪽의 값을 그대로 왼쪽의 변수에 저장
      ex) x = 5
  • 다른 할당 연산자들
    • 왼쪽의 변수와 오른쪽의 값을 특정한 연산으로 계산한 후, 그 결과를 왼쪽의 변수에 저장
      ex) x += 5 ⇒ x = x + 5
  • 우선순위
    • 모든 이항 연산자보다 낮으며, 오른쪽에서 왼쪽으로 평가된다.
      ex) x = y = z = 5
      1. z = 5
      2. y = z
      3. x = y

8. 화살표 연산자

Java 8에서 추가된 람다 표현식의 일부로, 함수형 프로그래밍을 가능하게 하는 연산자

8.1 람다 표현식

익명 함수(anonymous function)를 생성하는 간단한 방법

  • 함수를 하나의 식(expression)으로 취급할 수 있게 함

  • 람다 표현식은 주로 함수형 인터페이스(functional interface)의 구현체로 사용됨

    • 함수형 인터페이스
      • 추상 메소드가 하나만 있는 인터페이스
      • @FunctionalInterface 어노테이션을 붙인 인터페이스
    💡 람다 표현식으로 쓴다는 것은 `함수형 인터페이스를 구현한 익명 클래스`의 `익명 객체`를 만드는 것과 동일함
  • 문법

    (매개변수) -> {실행문}
  • 매개변수

    • 괄호로 묶어서 표현
    • 매개변수가 없으면 빈 괄호를 씀
    • 매개변수가 하나면 괄호를 생략할 수 있음
    • 타입은 생략 가능
  • 화살표(->)

    • 매개변수를 이용해서 실행문을 실행한다는 의미
  • 실행문

    • 중괄호로 묶어서 표현
    • 실행문이 한 줄이면 중괄호를 생략할 수 있음
    • 실행문이 반환문(return)이면 return 키워드도 생략할 수 있음
  • ex

    @FunctionalInterface
    interface Calculator {
        int calculate(int a, int b);
    }
    public class LambdaExample {
        public static void main(String[] args) {
            Calculator addition = (a, b) -> a + b; // 매개변수 a, b를 이용하여 a + b를 반환
            Calculator subtraction = (a, b) -> a - b; // 매개변수 a, b를 이용하여 a - b를 반환
    
            System.out.println(addition.calculate(3, 4)); // 7
            System.out.println(subtraction.calculate(7, 2)); // 5
        }
    }
  • 장점

  • 단점

    • 재사용이 불가능
    • 디버깅이 어려울 수 있음
    • 남발하면 코드가 지저분해질 수 있음
⭐ 화살표 연산자는 `함수`를 변수에 할당하거나, 매개변수로 전달하거나, 결과로 반환할 수 있게 해준다.

⇒ 함수가 일급 시민이다 == 일급 함수

8.2 일급 시민

  • 일급 시민 = 일급 객체 + 일급 함수
    • 다른 객체와 동일한 방식으로 다룰 수 있음
    • 변수나 데이터 구조 안에 저장될 수 있음
    • 함수나 메서드의 인자로 전달하거나 반환값으로 사용할 수 있음
  • 화살표 연산자를 통해 익명 객체를 일급 함수로 사용할 수 있게 됨

8.3 함수형 프로그래밍

  • 함수형 프로그래밍
    • 함수를 일급 시민으로 취급
      • 함수를 변수에 저장하거나 다른 함수의 인자로 전달하거나 반환값으로 사용할 수 있음
      • 이러한 기능은 함수를 사용하여 프로그램을 작성할 때 유용하게 사용될 수 있음

9. 삼항 연산자

피연산자를 세 개 받는 유일한 연산자로, 조건식에 따라 다른 값을 반환하는 연산자이다.

  • 조건 ? 참일 때 값 : 거짓일 때 값
    • 조건 부분에는 boolean 타입의 값이나 식이 올 수 있음
  • if-else 문과 비슷한 기능을 한 줄로 간단하게 표현할 수 있음
    • ex
      int max = (a > b) ? a : b
  • 삼항 연산자는 중첩해서 사용할 수도 있다. → 권장 x
    • ex
      int result = (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c)

10. 연산자 우선 순위

식을 평가할 때 연산자들의 실행 순서를 결정하는 규칙이다.

  • 산술 연산자 > 비트 연산자 > 관계 연산자 > 논리 연산자 > 할당 연산자
  • 같은 우선 순위의 연산자가 여러 개 있는 경우
    • 연산자의 결합 방향에 따라 실행 순서가 달라짐
      • 이항 연산자
        • 왼쪽 → 오른쪽
      • 할당 연산자 & 단항 연산자
        • 오른쪽 → 왼쪽
  • 괄호 안에 있는 식은 가장 먼저 실행됨
    • 가시성을 위해서 사용하기도 함

11. switch 연산자

하나의 값이나 식에 따라 다른 코드 블록을 실행하는 조건문이다.

  • break 문
    • 각 case 블록의 끝을 표시함
    • break 문이 없는 경우 다음 case 블록이 연속해서 실행되는 fall-through가 발생함
  • default
    • 식의 결과와 일치하는 case 레이블이 없는 경우에 실행할 코드를 지정할 수 있음
    • 필수는 아니지만, 권장됨
  • Java 12 - 새로운 표현식
    • 화살표 연산자 (->)

      • break문을 생략할 수 있음 → fall-through 방지
      public class NewSwitch {
      
          public static void main(String[] args) {
              int a = 10;
      
              String result = switch (a) {
                  case 5,6,7,8,9,10 -> "5 ~ 10";
                  case 11,12,13,14,15 -> "11 ~ 15";
                  default -> "모름";
              };
      
              System.out.println(result);
          }
      }
  • Java 13 - yield
    public class NewSwitch {
    
        public static void main(String[] args) {
            int a = 10;
    
            String result = switch (a) {
                case 5,6,7,8,9,10 -> {
                    System.out.println("yield1");
                    yield "5 ~ 10";
                }
                case 11,12,13,14,15 -> {
                    System.out.println("yield2");
                    yield "11 ~ 15";
                }
                default -> {
                    System.out.println("yield3");
                    yield "모름";
                }
            };
    
            System.out.println(result);
        }
    }
  • switch문의 return값이 있는 경우
    • 반드시 default를 지정해야 한다.

0개의 댓글