자바 연산자 (1)

Tina Jeong·2021년 1월 9일
0

Re-자바

목록 보기
5/16

연산자 챕터에 들어가기 전에 연산자와 피연산자에 대해 먼저 설명한다.

9+59

피연산자는 연산의 대상을 의미한다. 위의 예에서는 9와 59가 피연산자이고, +가 연산자이다.
일반적으로 연산자는 피연산자 두 개를 가지는 이항 연산자이다. 단항 연산자와 삼항연산자도 있는데, 해당 연산자들은 따로 언급할 것이다.

산술 연산자

boolean을 제외한 다른 원시 타입 피연산자들의 산술 연산과 관계된 연산자이다.

+ - * / % -(단항연산자)

연산자설명
+덧셈 연산자
-뺄셈 연산자
*곱셈 연산자
/나눗셈 연산자
%나머지 연산자

+ 연산자

덧셈 연산자이다.

덧셈 or concat ?

문자열 concat 연산자로도 쓰인다. 두 피연산자 중 하나가 문자열이라면 더하기 연산의 결과는 산술연산이 아닌 문자열 concat이다. 또한, 피연산자 타입의 순서에 따라 결과가 달라질 수 있으니 프로그래머의 의도에 따라 소괄호로 우선순위를 명시해주어야 한다. 문자열이 앞에 오면 뒤에도 concat 연산을 이어서 한다.

System.out.println("total"+3+4);
System.out.println(3+4+"total");
System.out.println("total"+(3+4));

결과

total34
7total
total7

알아서 타입 변환을 한다는 맥락에서 이어 말하면, 정수형과 실수형 간에 더하기 연산을 하면 자료형의 크기와 무관하게 실수형으로 변환된다.

System.out.println(4+3.0);

결과는 7.0

- 연산자

뺄셈 연산자이다. 더하기 연산자처럼 정수형과 실수형 뺄셈 연산을 하면 실수형으로 변환되고, 뺄셈 연산자가 아닌 음수 부호 단항 연산자(-2)로도 쓰인다.

ArithmeticException

나눗셈에서 피해야 할 부분은 두번째 피연산자가 zero인 경우이다. 두번째 피연산자가 정수형 0인 경우에는 다음과 같은 에러가 발생한다.

java.lang.ArithmeticException: / by zero

사실 정말 주의해야 할 건, 실수형에서 나눗셈 연산을 한 경우이다. ArithmeticException을 던지지 않기 때문이다.

System.out.println(4/0.0);
System.out.println(0.0/0.0);

결과를 찍어보면 각각 Infinity와 NaN-Not A Number로 출력된다.

% 연산자

modulo 연산자, 일명 나머지 연산자이다. /연산자는 나눗셈의 몫을 반환하지만, % 연산자는 나눗셈의 나머지를 반환한다. 예를 들어 30 % 7의 결과는 2이다.

관계 연산자

관계 연산자는 이항 연산자로서,두 항 간의 크고작음, 동치를 판별하는데 쓰이는 연산자이다.
판별의 결과는 truefalse이다. 보통 if, while, for문 등에서 판별 조건으로써 쓰인다.

연산자true인 경우
<왼쪽항이 오른쪽항 미만
>왼쪽항이 오른쪽항 초과
<=왼쪽항이 오른쪽항 이하
>=왼쪽항이 오른쪽항 이상
==왼쪽항값과 오른쪽항값이 같음
!=왼쪽항값과 오른쪽항값이 같지 않음

📌 일반적으로 등호= 가 동치를 의미하지만, 프로그래밍 언어에서는 ==이 동치를 의미하고, =는 동치가 아닌 값의 대입을 의미한다.

논리 연산자

논리 연산자는 이항 연산자 2개와 단항 연산자 1개가 있다. 두항의 조건이 모두 참인 경우(AND)인 &&와 둘중 하나가 참인 경우(OR)에 해당하는 ||, 항의 조건을 부정하는(NOT) !가 있다. 관계 연산자가 논리연산자를 구성하게 된다. 다음과 같이.

int a;
int b;
...
if((a>0) && (b!=0))

Short-circuit evaluation

논리 연산자가 자바에 적용될 때 Short-circuit evaluation으로 적용된다. short-circuit evaluation이란, AND나 OR로 구성된 조건식이 있을 때 첫번째항에서 AND,OR의 결과가 이미 도출되는 경우 다음항의 참/거짓을 체크하지 않고 넘어가는 것을 의미한다.

OR : ||

int a;
int b;
...
a=1;
if((a>0) || (b!=0))

위의 경우를 보면, a에 1이 대입 되어 a>0 조건이 참이 되었다. 고로, 둘 중 하나가 참인 경우를 만족하게 되었으므로 b!=0는 체크하지 않고 넘어간다.

AND : &&

int a;
int b;
...
a=-1;
if((a>0) && (b!=0))

이번에는 a에 -1을 대입하였고, a>0가 거짓이 되었으므로 두항 모두 참이어야 하는 AND 조건을 만족하지 못한다. 그래서, b!=0는 체크하지 않고 넘어간다.

비트 연산자

비트 연산자는 로우레벨연산을 지원하는 연산자로, 비트 단위로 연산을 할 수 있다.

연산자설명
&두 비트모두 1인 경우 1로 결과 도출
|두 비트 중 하나가 1인 경우 1로 결과 도출
^두 비트의 값이 다른 경우 1로 결과 도출 같으면 0
~비트값 반전. 0이면 1, 1이면 0으로
<<왼쪽으로 shift 연산
>>sign bit가 1이면 1채워서, 0이면 0 채워서 오른쪽으로 shift 연산
>>>sign bit 값과 무관하게 0 채워서 오른쪽으로 shift 연산

int bit1 = 0b00000011;
int bit2 = 0b00010011;
System.out.println(Integer.toString(bit1 & bit2, 2));
System.out.println(Integer.toString(bit1 | bit2, 2));
System.out.println(Integer.toString(bit1 ^ bit2, 2));
System.out.println(Integer.toString(~bit1, 2));
System.out.println(Integer.toString(bit1 << 2, 2));
int bit3 = -50;
System.out.println(Integer.toString(bit3, 2));
System.out.println(Integer.toUnsignedString(bit3 >> 2, 2));
System.out.println(Integer.toString(bit3 >>> 2, 2));

결과

11
10011
10000
-100
1100
-110010
11111111111111111111111111110011
111111111111111111111111110011

📌 unsigned shift 연산과 signed shift 연산을 비교하기 위해 Integer.toUnsignedString 메소드를 활용하였다. 마지막 줄의 unsigned shift 연산의 결과를 보면 그 윗줄의 signed 연산과 다르게 MSB 2개가 0인 것을 확인할 수 있다.

비트연산자인데..논리 연산자? ㄴㅇㄱ

사실은 &, |, ^가 논리 연산자로도 쓰일 수 있다. c와 다르게, 자바에서는 조건식 결과값이 숫자가 아니라 무조건 참 거짓으로 판별되어야 한다. 조건식 결과가 숫자인 경우 컴파일러의 불평이 바로 나온다. 때문에, 참거짓 조건식이라면 써도 문제가 없는 것이다.

boolean으로 판별되는 조건식에는 &, |, ^ 연산자를 써줘도 논리 연산으로 동작한다.

int a = 0;
int b = 0;

if (a >= 0 & b == 0) {
      System.out.println(true);
}

if (a >= 0 | b == 0) {
      System.out.println(true);
}
if (a < 0 ^ b == 0) {
      System.out.println(true);
}

결과는 모두 true로 나온다.

대입 연산자

기본적인 대입 연산자는 =이다. 대입 연산자는 왼쪽 value lvalue에 오른쪽 value rvalue가 대입되는 것이 기본 개념이다. lvalue는 보통 메모리에 할당되는 변수를 의미하고, rvalue는 또 다른 변수나 리터럴이 될 수 있다.

lvalue = lvalue or rvalue

자바는 이외에도 11개의 대입 연산자를 지원한다. 5개의 산술대입 연산자와 6개의 비트 대입 연산자를 지원하는데, 여기서는 산술 대입 연산자만 정리할 것이다.

산술 대입 연산자

연산자설명
+=덧셈 연산자
-=뺄셈 연산자
*=곱셈 연산자
/=나눗셈 연산자
%=나머지 연산자

산술대입연산자는 자기 자신이 포함된 arithmetic statement의 abbreviation이다. 무슨 말일까?

int a =1;
a = a + 2;
a += 2;

두번째 줄의 statment를 보면 a에 a의 초기값인 1과 정수 리터럴 2를 대입한 것을 볼 수 있다. 해당 줄을 abbreviate하면 세번째 줄이 된다. 즉, 똑같은 표현이다. 나머지 산술 연산자들도 동일한 원리로 사용할 수 있다.

주의 ‼

arr[i++] += 2;
arr[i++] = arr[i++] +2;

자기 자신이 포함된 산술 연산을 줄이면 모두 동일한 표현이며, 또 동일한 결과가 나올까? 그렇지 않으니 주의해야 한다. 단항연산자인 증감연산자++, --를 설명하지 않았는데, 증감연산자는 항의 값을 1만큼 증가 시키거나 감소시키는 연산자를 의미한다. 증감연산자의 위치가 항의 prefix에 있다면 해당 라인에서 바로 증감되고, 항의 postfix에 있다면 다음 줄에서 적용된다.

위의 예시의 첫번째줄을 보면 배열 arr의 i index에 2가 더해지고, 다음줄에서 i index가 1증가한다. 두번째 줄은 배열 arr의 i index에 2가 더해지고, 다음줄에서 i index가 2증가한다. 보통은 첫번째줄을 의도하고 사용하니 큰 문제는 발생하지 않겠지만, 어쨌든 대입 연산자를 증감연산자와 함께 사용할 때는 주의해야 한다.

삼항연산자

자바에서 지원하는 유일한 삼항 연산자에 대해 알아본다.

조건 ? 리턴값1: 리턴값2

첫번째 피연산자부분에는 반드시 참/거짓으로 판별되는 boolean 조건식이 나와야 한다. 조건식이 참이면 두번째 피연산자인 리턴값1을 반환하고, 거짓이면 리턴값2를 반환한다. 리턴값1과 리턴값2는 동일한 타입이어야 한다. 아래는 예시이다. if문의 내용과 삼항연산자의 결과값은 동일하다.

int result = 0;
int a,b;
...
if(a>b) result =1;
else result =2;

result = (a>b)? 1:2;

참고
https://www.cs.odu.edu/~zeil/cs250PreTest/latest/Public/operators/index.html
https://en.wikipedia.org/wiki/Short-circuit_evaluation
https://www.geeksforgeeks.org/lvalue-and-rvalue-in-c-language/
Java in a Nutsell, 7th Edition

계속해서 문서를 업데이트하고 있습니다. 언제든지 댓글피드백 남겨주세요. 😉

profile
Keep exploring, 계속 탐색하세요.

0개의 댓글