연산자

ahnjs·2022년 11월 16일
0
post-thumbnail

목표

자바가 제공하는 다양한 연산자를 학습.

학습내용

  • 산술 연산자
  • 비트 연산자
  • 관계 연산자
  • 논리 연산자
  • instanceof
  • assignment(=) operator
  • 화살표(->) 연산자
  • 3항 연산자
  • 연산자 우선 순위
  • (optional) Java 13. switch 연산자

연산자와 연산식

  • 필요로 하는 피연산자의 수에 따라 단항, 이항, 삼항 연산자로 구분
  • 연산식은 반드시 하나의 값을 산출

연산 (operations)

프로그램에서 데이터를 처리하여 결과를 산출하는 것

연산자 (operator)

연산에 사용되는 표시나 기호

피연산자 (operand)

연산되는 데이터

연산식 (expressions)

연산자와 피연산자를 이용하여 연산의 과정을 기술한 것


산술 연산자

  • 사칙 연산을 하는 연산자
  • boolean 타입을 제외한 모든 기본 타입에 사용할 수 있음
산술 연산자설명
+두개의 값을 더한다.
-왼쪽 기준으 ㅣ값에서 오른쪽 값으로 뺀다.
*두개의 값을 곱한다.
/왼쪽 기준의 값에서 오른쪽 값으로 나눈다.
%왼쪽 기준의 값에서 오른쪽 값으로 나눈 후, 나머지를 가져온다.

산술연산 우선순위

  1. 기본 처리는 왼쪽에서 우측으로 이동한다.
  2. 괄호가 존재하면, 괄호를 가장 먼저 계산한다.
  3. 곱셈과 나눗셈, 나머지 연산(나머지 연산은 궁극적으로 나눗셈과 같습니다)이 덧셈, 뺄셈보다 먼저 연산된다.

타입이 동일하지 않을 경우

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

  • 피연산자들이 모두 정수 타입이고, int 타입 (4 byte)보다 크기가 작은 타입일 경우
    • 모두 int 타입으로 변환 후, 연산 수행 ⇒ 결과는 int
  • 피연산자들이 모두 정수 타입이고, long 타입이 있을 경우
    • 모두 long 타입으로 변환 후, 연산 수행 ⇒ 결과는 long
  • 피연산자 중 실수 타입 (float, double)이 있을 경우
    • 크기가 큰 실수 타입으로 변환 후, 연산 수행 ⇒ 결과는 실수 타입

산술연산에서의 주의점

  • 오버플로우 탐지
    • 연산 후의 산출값이 산출 타입으로 충분히 표현 가능한지 살펴봐야 함
  • 정확한 계산은 정수 사용
    • 실수 타입의 경우 BigDecimal 사용
  • NaN 과 Infinity 연산
  • 입력값의 NaN 검사

자바의 NaN

  • Java에서 "Not a Number"를 나타낸다.
  • 오버플로 및 오류를 나타내는 특수 부동 소수점 값이다. 부동 소수점 숫자를 0으로 나누거나 음수의 제곱근을 계산할 때 생성.
public class NaN
{
    public static void main(String[]args)
    {
        System.out.println(0.0 / 0.0);	  //zero divided by zero
        System.out.println(Math.sqrt(-1)); //take sqrt of negative number
        System.out.println(10.0 % 0);      //taking mod by zero
    }
}

비트 연산자

비트 연산자는 비트(bit) 단위로 논리 연산을 할 때 사용하는 연산자이다. 비트 단위로 왼쪽이나 오른쪽으로 전체 비트를 이동하거나, 1의 보수를 만들 때도 사용된다.

비트 연산자설명
&대응되는 비트가 모두 1이면 1을 반환함. (비트 AND 연산)
|대응되는 비트 중에서 하나라도 1이면 1을 반환함. (비트 OR 연산)
^대응되는 비트가 서로 다르면 1을 반환함. (비트 XOR 연산)
~비트를 1이면 0으로, 0이면 1로 반전시킴. (비트 NOT 연산, 1의 보수)
<<명시된 수만큼 비트들을 전부 왼쪽으로 이동시킴. (left shift 연산)
>>부호를 유지하면서 지정한 수만큼 비트를 전부 오른쪽으로 이동시킴. (right shift 연산)
>>>지정한 수만큼 비트를 전부 오른쪽으로 이동시키며, 새로운 비트는 전부 0이 됨.

비트 반전 연산자 (~)

  • 정수 타입 (byte, short, int, long)의 피연산자에만 사용
  • 피연산자를 2진수로 표현했을 때 비트값인 0 -> 1, 1 -> 0으로 반전
  • 연산 후, 부호 비트인 최상위 비트를 포함하여 모든 비트가 반전됨
    • 부호가 반대인 새로운 값 산출됨
  • 산출 타입은 int 타입

비트 연산자 (&, |, ^, <<, >>, >>>)

  • 데이터 비트 (bit) 단위로 연산
  • 0 과 1이 피연산자가 됨
  • 0과 1로 표현이 가능한 정수 타입만 비트 연산을 할 수 있음(실수 타입은 불가)
  • 비트 논리 연산자 (&, |, ^, ~) ⇒ 0과 1을 연산
  • 비트 이동 연산자 (<<, >>, >>>) ⇒ 비트를 좌측 또는 우측으로 이동하는 연산자

비트연산을 사용하는 이유

  • 컴퓨터가 기존 자료형(int,char 등등) 을 비트로 변환하는 작업을 사용자가 미리 해주기 때문에 속도가 빠르다.
  • 따라서 데이터가 크면 클수록 속도에서 우위를 가져 올 수 있다.
  • 암호화에도 사용하기도 한다.

관계 연산자

관계 연산자설명
a < ba 가 b 보다 작은가?
a > ba 가 b 보다 큰가?
a <= ba 가 b 보다 작거나 같은가?
a >= ba 가 b 보다 크거나 같은가?
a == ba 와 b 가 같은가?
a != ba 와 b 가 다른가?
  • 대소 또는 동등을 비교해서 boolean 타입인 true / false를 산출
  • 대소 연산자는 boolean 타입을 제외한 기본 타입에 사용 가능
  • 동등 연산자는 모든 타입에 사용 가능
  • 비교 연산자는 조건문, 반복문에 주로 이용되어 실행 흐름 제어
  • 피연산자가 char 타입이면, 유니코드 값으로 비교 연산 수행
  • 타입 변환을 통해 피연산자의 타입을 일치 시킴
'A' == 65 // true, 'A' 가 int 타입으로 변환되어 65가 된 다음 65 == 65로 비교
3 == 3.0 // int 타입인 3을 double 타입으로 변환한 후 3.0 == 3.0 으로 비교

실수

0.1 == 0.1f // false
(float) 0.1 == 0.1f
  • 이진 포맷의 가수를 사용하는 모든 부동소수점 타입은 0.1을 정확히 표현 할 수 없다.
  • 0.1f는 0.1의 근사값으로 표현되어 0.1000000149011612 와 같은 값이 되기 때문에, 0.1보다 큰 값이 됨
  • 피연산자를 모두 float 타입으로 강제 타입 변환하여 비교 연산

String

  • String 타입의 문자열을 비교할 때는 대소 연산자를 사용할 수 없고, 동등 비교 연산자는 사용 가능하나 문자열이 같은지 다른지를 비교할땐 equals() 메소드 사용.
String strVar1 = "값1";
String strVar2 = "값1";
String strVar3 = new String("값1");

// 결과
strVar1 == strVar2 // true
strVar2 == strVar3 // false
strVar2.equals(strVar3) // true

논리 연산자

  • 논리곱, 논리합, 배타적 논리합, 논리 부정을 수행
  • 피연산자로 blooean 타입만 사용 가능
  • 비트연산과 차이 Short-circuit evaluation
논리 연산자설명
&&논리식이 모두 참이면 참을 반환함. (논리 AND 연산)
||논리식 중에서 하나라도 참이면 참을 반환함. (논리 OR 연산)
!논리식의 결과가 참이면 거짓을, 거짓이면 참을 반환함. (논리 NOT 연산)

instanceof

instanceof 비교 연산자

  • 어떤 객체가 어떤 클래스의 인스턴스인지 확인하기 위한 연산자
  • 좌항 : 객체, 우항 : 타입
  • 좌항의 객체가 우항의 인스턴스이면 true.
    • 즉, 우항의 타입으로 객체가 생성되었다면 true, 아니면 false
  • instanceof 연산자는 매개값의 타입을 확인할 때 주로 사용
  • 다운캐스팅의 경우 instanceof 연산자로 확인해야 한다.
    • 확인하지 않고 강제 타입 변환을 시도한다면 ClassCastException발생

assignment(=) operator

  • 대입 연산자는 변수에 값을 대입할 때 사용하는 이항 연산자이며, 피연산자들의 결합 방향은 오른쪽에서 왼쪽이다.
  • 자바에서는 대입 연산자와 다른 연산자를 결합하여 만든 다양한 복합 대입 연산자를 제공한다.
대입 연산자설명
=왼쪽의 피연산자에 오른쪽의 피연산자를 대입함.
+=왼쪽의 피연산자에 오른쪽의 피연산자를 더한 후, 그 결괏값을 왼쪽의 피연산자에 대입함.
-=왼쪽의 피연산자에서 오른쪽의 피연산자를 뺀 후, 그 결괏값을 왼쪽의 피연산자에 대입함.
*=왼쪽의 피연산자에 오른쪽의 피연산자를 곱한 후, 그 결괏값을 왼쪽의 피연산자에 대입함.
/=왼쪽의 피연산자를 오른쪽의 피연산자로 나눈 후, 그 결괏값을 왼쪽의 피연산자에 대입함.
%=왼쪽의 피연산자를 오른쪽의 피연산자로 나눈 후, 그 나머지를 왼쪽의 피연산자에 대입함.
&=왼쪽의 피연산자를 오른쪽의 피연산자와 비트 AND 연산한 후, 그 결괏값을 왼쪽의 피연산자에 대입함.
|=왼쪽의 피연산자를 오른쪽의 피연산자와 비트 OR 연산한 후, 그 결괏값을 왼쪽의 피연산자에 대입함.
^=왼쪽의 피연산자를 오른쪽의 피연산자와 비트 XOR 연산한 후, 그 결괏값을 왼쪽의 피연산자에 대입함.
<<=왼쪽의 피연산자를 오른쪽의 피연산자만큼 왼쪽 시프트한 후, 그 결괏값을 왼쪽의 피연산자에 대입함.
>>=왼쪽의 피연산자를 오른쪽의 피연산자만큼 부호를 유지하며 오른쪽 시프트한 후, 그 결괏값을 왼쪽의 피연산자에 대입함.
>>>=왼쪽의 피연산자를 오른쪽의 피연산자만큼 부호에 상관없이 오른쪽 시프트한 후, 그 결괏값을 왼쪽의 피연산자에 대입함.

화살표(->) 연산자

Java 1.8에 추가된 람다식에서 사용되는 연산자

람다식

  • 식별자 없이 실행 가능한 함수
  • 함수인데 함수를 따로 만들지 않고 코드한줄에 함수를 써서 그것을 호출하는 방식

화살표(->) 연산자

매개변수를 이용하여 중괄호를 실행한다는 의미

  • 람다식 없을 때
Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.print("Run method");
            }
        };
  • 람다식을 이용한 표현
Runnable r = ()-> System.out.print("Run method");

3항 연산자

조건식 ? 반환값1 : 반환값2
  • 자바에서 유일하게 피연산자를 세 개나 가지는 조건 연산자
  • 문법
    • 물음표(?) 앞의 조건식에 따라 결괏값이 참(true)이면 반환값1을 반환하고, 결괏값이 거짓(false)이면 반환값2를 반환한다.

연산자 우선 순위

  • 대부분의 연산자는 왼쪽에서부터 오른쪽으로 연산을 시작
  • 단항 연산자 (++,- -, ~ , !), 부호 연산자 (+,-), 대입 연산자 (=, += ...) 는 오른쪽에서 왼쪽으로 연산됨

Java 13 switch 연산자

  • 기존 switch문
public String getGrade(int score) {
		String grade = "";
		switch (score) {
				case score >= 90:
						grade = "A";
						break;
				case score >= 80:
						grade = "B";
						break;
				case score >= 70:
						grade = "C";
						break;
				case score >= 60:
						grade = "D";
						break;
				case score >= 50:
						grade = "E";
						break;
				default:
						grade = "F";
						break;
		}

}

Java 13의 switch 문

  • case문 내에 여러 개의 값을 이용할 수 있다.
  • 블록을 사용 가능
  • break로 값을 반환하던 것이 yield를 이용하도록 변경
private static int getValueViaYield(String mode) {
        int result = switch (mode) {
            case "a", "b":
                yield 1;
            case "c":
                yield 2;
            case "d", "e", "f":
                // do something here...
                System.out.println("Supports multi line block!");
                yield 3;
            default:
                yield -1;
        };
        return result;
}

추가

  • 여러 연산을 통해 중간 값 구하기
public static void main(String[] args) {
		int start = 2_000_000_000;
		int end = 2_100_000_000;
		
		int mid = (start + end) / 2; // 오버플로우 발생의 가능성이 있음
		int mid = start + (end - start) / 2;
		int mid = (start + end) >>> 1;
}

ref

0개의 댓글