[백기선님_자바_스터디] 3주차 - 연산자

시나브로·2021년 7월 16일
0
post-thumbnail

0. 연산자



연산자는 연산을 수행하는 기호를 말한다.

연산자가 연산을 수행하기 위해서는 반드시 연산의 대상이 있어야 하는데, 이를 피연산자(operand)라고 한다. 피연산자로 상수, 변수 또는 식(계산식) 등을 사용할 수 있다.



1. 산술 연산자


산술 연산자에는 사칙 연산자 +, -, *, /와 나머지 연산자 %가 있다.


산술 연산자 특징

  • boolean 타입을 제외한 모든 기본 타입에 사용할 수 있다

  • 피연산자들의 타입이 동일하지 않을 경우 피연산자들의 타입을 일치시킨 후 연산을 수행한다

    • 피연산자들이 모두 정수 타입이고, int 타입 (4 byte)보다 크기가 작은 타입일 경우
      → 모두 int 타입으로 변환 후, 연산 수행 ⇒ 결과는 int
    • 피연산자들이 모두 정수 타입이고, long 타입이 있을 경우
      → 모두 long 타입으로 변환 후, 연산 수행 ⇒ 결과는 long
    • 피연산자 중 실수 타입 (float, double)이 있을 경우
      → 크기가 큰 실수 타입으로 변환 후, 연산 수행 ⇒ 결과는 실수 타입
  • 자바 가상 기계 (JVM)가 기본적으로 32비트 단위로 계산하기 때문에 long을 제외한 정수는 모두 int로 계산한다.

ex)

byte byte1 = 1;
byte byte2 = 2;
byte byte3 = byte1 + byte2; // 컴파일 에러 
// long 타입을 제외한 정수의 산술 연산은 무조건 int 타입으로 변환 후 연산을 수행하고, 
// 산출 타입도 int 이기 때문
int result = byte1 + byte2; // 이게 맞는 코드
//2.5를 얻고 싶다면, 아래와 같이 피연산자 중 최소한 하나는 실수 타입이어야 함
int int1 = 10;
int int2 = 4;
int result2 = int1 / int2; // 2
double result3 = int1 / int2; // 2.5가 아닌 2.0

//char 타입도 정수 타입이므로 산술 연산이 가능함 (결과는 int)
double result3 = (int1*1.0) / int2;
double result3 = (double) int1 / int2;
double result3 = int1 / (double) int2;

char c1 = 'A' + 1;
char c2 = 'A';

char c3 = c2 + 1; // 컴파일 에러
// char를 얻고 싶으면, 강제 타입 변환 (캐스팅) 필요
char c4 = (char) (c2 + 1);

산술 연산자 주의점


  • 오버플로우 탐지

    • 연산 후의 산출값이 산출 타입으로 표현 가능한 범위인지 확인해야한다
  • 정확한 계산은 정수 사용

    • 정확하계 계산해야 할 때는 부동소수점 (실수) 타입을 사용하지 말아야 한다
    • 부동소수점 타입 (float, double)은 0.1을 정확히 표현할 수 없어 근사치로 처리하기 때문이다
  • NaN 과 Infinity 연산

    • / 나 % 연산자는 좌측 피연산자가 정수 타입인 경우에, 나누는 수인 우측 피연산자는 0을 사용할 수 없다
    • 실수 타입인 0.0 또는 0.0f 로 나누면 ArithmeticException 이 발생하지 않는다
      • / 연산의 결과는 Infinity (무한대) 값을 가진다
        5 / 0.0 => Infinity
      • % 연산의 결과는 NaN (Not a Number) 을 가진다
        5 % 0.0 => NaN
    • 프로그램 코드에서 결과가 Infinity 또는 NaN인지 확인하려면 아래 두 메소드 이용할 수 있다
      • Double.isInfinite()
      • Double.isNaN()
  • 입력값의 NaN 검사

    • 부동소수점 (실수) 을 입력받을 때는 반드시 NaN 검사를 해야한다
    • NaN 검사는 Double.isNaN() 메소드를 사용해야 한다



2. 비트 연산자



비트 연산자는 피연산자를 비트단위로 논리 연산한다. 피연산자를 이진수로 표현했을 때의 각 자리를 규칙에 따라 연산을 수행하며, 피연산자로 실수는 허용하지 않는다. 오직 정수(문자 포함)만 허용된다.

구분

  • 비트 논리 연산자 (&, |, ^, ~) ⇒ 0과 1을 연산
  • 비트 이동 연산자 (<<, >>, >>>) ⇒ 비트를 좌측 또는 우측으로 이동하는 연산자

비트 논리 연산자



비트 이동 연산자






3. 관계 연산자



관계 연산자(Relational Operator) 또는 비교 연산자(Comparing Operator)라 불리는 연산자는 두 피연산자를 비교하는 데 사용되는 연산자이다. 주로 조건문과 반복문의 조건식에 사용되며, 연산결과는 오직 true와 false 둘 중의 하나이다.


대소비교 연산자 (< > <= >=)

두 피연산자의 값의 크기를 비교하는 연산자로 참이면 true를, 거짓이면 false를 반환한다.


등가비교 연산자 (== !=)

두 피연산자의 값이 같은지 또는 다른지를 비교하는 연산자이다.

기본형의 경우 변수에 저장되어 있는 값이 같은지를 알 수 있고, 참조형의 경우 객체의 주소값을 저장하기 때문에 두 개의 피연산자(참조변수)가 같은 객체를 가리키고 있는지를 알 수 있다.




4. 논리 연산자



논리 연산자는 둘 이상의 조건을 ‘그리고(AND)’나 ‘또는(OR)’으로 연결하여 하나의 식으로 표현할 수 있게 한다.



&&와 & 차이

  • && 는 앞의 피연산자가 false이면 뒤의 피연산자를 평가하지 않고 바로 false 를 결과로 냄
  • & 연산자는 두 개의 피연산자 모두를 평가해서 산출 결과를 냄
  • & 보다 &&가 더 효율적으로 동작
  • ||와 | 도 마찬가지로 동작



5. instanceof



  • instanceof연산자는 참조변수가 참조하고 있는 인스턴스의 실제 타입을 알아보기 위해 사용한다.

  • 주로 조건문에 사용되며 좌측에는 참조변수가, 우측에는 타입(클래스명)이 피연산자로 위치한다.

  • 연산 결과로 boolean값인 true와 false 중의 하나를 반환한다. 값이 null인 참조변수에 대해 수행할 경우 false를 결과로 얻는다.

  • instanceof를 이용한 연산결과로 true를 얻었다는 것은 참조변수가 검사한 타입으로 형변환이 가능하다는 것을 뜻한다.

  • 조상타입의 참조변수로 자손타입의 인스턴스를 참조할 수 있기 때문에, 참조변수의 타입과 인스턴스의 타입이 항상 일치하지는 않는다.

ex)

public void method(Parent parent) {
  	// Parent 매개변수가 참조하는 객체가 Child인지 조사
    if (parent instanceof Child) {
        Child child = (Child) parent;
    }
}



6. assignment(=) operator



  • 대입 연산자(assignment operator)는 변수와 같은 저장공간에 값 또는 수식의 연산결과를 저장하는데 사용된다.

  • 이 연산자는 오른쪽 피연산자의 값(식이라면 평가값)을 왼쪽 피연산자에 저장한다. 그리고 저장된 값을 연산결과로 반환한다.

  • 대입 연산자는 연산자들 중에서 가장 낮은 우선순위를 가지고 있기 때문에 식에서 가장 마지막에 수행된다.

  • 연산 진행 방향이 오른쪽에서 왼쪽이기 때문에 x = y = 3;을 시행하면 y = 3이 먼저 수행되고 x = y가 수행된다.


복합 대입 연산자




7. 화살표(->) 연산자



  • JDK 1.8부터 자바에 추가된 람다식(Lambda expression)의 도입으로 인해 자바는 객체지향언어인 동시에 함수형 언어가 되었다.

람다식이란?

  • 람다식(Lambda expression)은 메서드를 하나의 ‘식(expression)’으로 표현한 것이다.

  • 메서드를 람다식으로 표현하면 메서드의 이름과 반환 값이 없어지므로, 람다식을 ‘익명 함수(anonymous function)’라고도 한다.

ex)

 int[] arr = new int[5];
 Arrays.setAll(arr, (i) -> (int)(Math.random() * 5) + 1);

모든 메서드는 클래스에 포함되어야 하므로 클래스를 생성하고, 객체도 생성해야만 메서드를 호출할 수 있다.

그러나 람다식은 이 모든 과정없이 람다식 자체만으로도 메서드의 역할을 대신할 수 있다.

람다식은 메서드의 매개변수로 전달되어지는 것이 가능하고, 메서드의 결과로 반환될 수도 있다. 람다식으로 인해 메서드를 변수처럼 다루는 것이 가능해진 것이다.

자세한 설명은 Java8 시리즈에서 다루도록 하겠다



8. 3항 연산자



  • 조건 연산자 ? :는 조건식, 식1, 식2 총 세 개의 피연산자를 필요로 하는 3항 연산자이며, 조건 연산자가 유일한 3항 연산자이다.

  • 조건 연산자는 첫 번째 피연산자인 조건식의 평가결과에 따라 다른 결과를 반환한다. 조건식의 평가결과가 true이면 식1이, false이면 식2가 결과로 반환된다.

ex)

    result = (x > y) ? x : y; // x > y가 true이면 x, false이면 y가 변수 result에 저장된다.



9. 연산자 우선 순위



  • 식에 사용된 연산자가 둘 이상인 경우, 연산자의 우선순위에 의해서 연산순서가 결정된다.

  • 수학에서 배웠듯이 곱셈과 나눗셈(*, /)이 덧셈과 뺄셈(+, -)보다 우선순위가 높다는 것을 알고 있다.




10. Java 13. switch 연산자



Java 12

Java 12에서 Switch문이 확장되었다.

복수의 case

case에 복수의 값을 설정할 수 있게 되었다.

switch(weekday) {
    case MONDAY, FRIDAY:
        time = "10:00 - 18:00";
        break;
    case TUESDAY, THURSDAY:
        time = "10:00 - 14:00";
        break;
    default:
        time = "휴일";
  }

지시자(->) 문법

지시자(->)를 사용하여 break를 생략할 수 있게 되었다.

  String time;

  switch(weekday) {
    case MONDAY, FRIDAY -> time = "10:00 - 18:00";
    case TUESDAY, THURSDAY -> time = "10:00 - 14:00";
    default -> time = "휴일";
  }

블록을 사용하여 여러가지 처리를 작성할 수 있게 되었다.
  String time;

  switch(weekday) {
    case MONDAY, FRIDAY -> {
      var endTime = getEndTime();
      time = "10:00 - " + endTime;
    }
    case TUESDAY, THURSDAY -> time = "10:00 - 14:00";
    default -> time = "휴일";
  }

Switch 식

Switch를 식으로도 사용할 수 있다. 지시자 문법을 사용하지 않는 경우나 지시자 문법에 블록을 사용한 경우 break로 값을 반환한다.

    String time = switch(weekday) {
      case MONDAY, FRIDAY -> {
        var endTime = getEndTime();
        break "10:00 - " + endTime;
      }
      case TUESDAY, THURSDAY -> "10:00 - 14:00";
      default -> "휴일";
    };

Java 13

break로 값을 반환하는 문법이 yield로 변경되었다.


Java 12

    String result = switch(code) {
      case 1:
        break "code 1";
      case 2:
        break "code 2";
      default:
        break "default";
    };

    System.out.println(result);

Java 13

    String result = switch(code) {
      case 1:
        yield "code 1";
      case 2:
        yield "code 2";
      default:
        yield "default";
    };

    System.out.println(result);







참조


profile
Be More!

0개의 댓글