연산
식과 연산자
주어진 식(expression)을 계산하여 결과를 얻어내는 과정을 얻어내는 과정을 연산이라고 합니다.
식에는 연산자와 피연산자로 나누어져 있습니다.

식에서 +, >, == 을 연산자(operator), 데이터를 피연산자(operand)라고 합니다.
| 연산의 종류 | 연산자 | 연산의 종류 | 연산자 |
| 증감 | ++ -- | 비트 | & | ^ ~ |
| 산술 | + - * / % | 논리 | && || ! ^ |
| 시프트 | >> << >>> | 조건 | ? : |
| 비교 | > < >= <= == != | 대입 | = *= /= += -= &= ^= |= <<= >>= >>>= |
연산자 우선순위
식에 여러 개의 연산자가 있는 경우, 우선순위가 높은 연산자를 높인 연산자를 먼저 처리합니다.
우선순위가 동일하면 왼쪽에서 오른쪽으로 처리하나, 대입 연산자, --, ++, +(양수 부호), -(음수 부호), !, 타입 변환 연산자 등은 오른쪽에서 왼쪽으로 처리합니다.
괄호는 항상 최우선적으로 처리합니다.
식에 다수의 괄호가 포함된 경우 왼쪽에서 오른쪽으로 처리하며, 괄호가 다시 괄호를 포함한 경우는 안쪽부터 먼저 처리합니다.
복잡한 수식의 경우는 괄호로 묶어서 표시하는 것이 코드의 가독성을 높이며 예기치 못한 오류 발생을 줄입니다.

산술 연산
더하기(+), 빼기(-), 곱하기(*), 나누기(/), 나머지(%)의 5개입니다.
정수 연산에서 /는 몫을 %는 나머지를 구합니다.
| 69 / 10 = 6 <- 몫 6 69 % 10 = 9 <- 나머지 9 |
| 연산자 | 의미 | 예 | 결과 |
| + | 더하기 | 25.5 + 3.6 | 29.1 |
| - | 빼기 | 3 - 5 | -2 |
| * | 곱하기 | 2.5 * 4.0 | 10.0 |
| / | 나누기 | 5 / 2 | 2 |
| % | 나머지 | 5 % 2 | 1 |
% 연산자는 다음과 같이 정수 n이 홀수인지 짝수인지 구분할 때 유용하게 활용됩니다.
int r = n % 2; // n이 홀수이면 r은 1, 짝수이면 r은 0
다음과 같이 n 값이 3의 배수인지 확인하기 위해서도 활용됩니다.
int s = n % 3; // n이 3의 배수이면 s는 0
/와 % 산술 연산
import java.util.Scanner;
public class ArithmeticOperator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("정수를 입력하세요: ");
int time = scanner.nextInt(); // 정수 입력
int second = time % 60; // 60으로 나눈 나머지는 초
int minute = (time / 60) % 60; // 60을 너눈 묷을 60으로 나눈 나머지는 분
int hour = (time / 60) / 60; // 60으로 나눈 몫을 60으로 나눈 몫은 시간
System.out.print(time + "초는 ");
System.out.print(hour + " 시간, ");
System.out.print(minute + "분, ");
System.out.println(second + "초입니다.");
scanner.close();
}
}
실행 결과
정수를 입력하세요: 5000
5000초는 1 시간, 23분, 20초입니다.
증감 연산
++, --의 두 가지입니다.
피연산자의 앞 또는 뒤에 붙어 값을 1증가시키거나 1감소시킵니다.
int a = 1;
a++; // a값 1 증가, a는 2
++a; // 다시 a값 값 1증가. a는 3
연산자가 변수의 앞에 붙을 때 전위 연산자라고 부르며, 뒤에 붙을 때 후위 연산자라고 부릅니다.

| 연산자 | 내용 | 연산자 | 내용 |
| a++ | a를 1증가하고 증가 전의 값 반환 | ++a | a를 1증가하고 증가된 값 반환 |
| a-- | a를 1감소하고 감소 전의 값 반환 | --a | a를 1 감소하고 감소된 값 반환 |
대입 연산
연산자의 오른쪽 식의 결과를 왼쪽에 있는 변수에 대입합니다.
int a = 1, b = 3;
a = b; // b 값을 a에 대입하여 a = 3
a += b; // a = a + b의 연산이 이루어져, a = 6. b는 3 그대로
| 대입 연산자 | 내용 | 대입 연산자 | 내용 |
| a = b | b값을 a에 대입 | a &= b | a = a & b와 동일 |
| a +=b | a = a + b와 동일 | a ^=b | a = a ^ b와 동일 |
| a -= b | a = a - b와 동일 | a |= b | a = a | b와 동일 |
| a *= b | a = a * b와 동일 | a <<= b | a = a << b와 동일 |
| a /= b | a = a / b와 동일 | a >>= b | a = a >> b와 동일 |
| a %= b | a = a % b와 동일 | a >>>= b | a = a >>> b와 동일 |
대입 연산자와 증감 연산자 사용
public class AssignmentIncOperator {
public static void main(String[] args) {
int a = 3, b = 3, c = 3;
// 대입 연산자
a += 3; // a = a + 3 = 6
b *= 3; // b = b * 3 = 9;
c %= 2; // c = c % 2 = 1
System.out.println("a=" + a + ", b=" + b + ", c=" + c);
int d = 3;
// 증감 연산자 사례
a = d++;
System.out.println("a=" + a + ", d=" + d);
a = ++d; // d = 5, a = 5
System.out.println("a=" + a + ", d=" + d);
a = d--; // a = 5, d = 4
System.out.println("a=" + a + ", d=" + d);
a = --d; // d = 3, a = 3
System.out.println("a=" + a + ", d=" + d);
}
}
실행 결과
a=6, b=9, c=1
a=3, d=4
a=5, d=5
a=5, d=4
a=3, d=3
비교 연산와 논리 연산
두 개의 피연산자를 비교하여 true 또는 false의 논리 값을 내는 연산자입니다.
논리 연산자는 논리 값을 대상으로 AND, OR, XOR, NOT의 논리 연산을 하여 논리 값을 내는 연산자입니다.
| 연산자 | 내용 | 에제 | 결과 |
| a < b | a가 b보다 작으면 true | 3 < 5 | true |
| a > b | a가 b보다 크면 true | 3 > 5 | false |
| a <= b | a가 b보다 작거나 같으면 true | 1 <= 0 | false |
| a >= b | a가 b보다 크거나 같으면 true | 10 >= 10 | true |
| a == b | a가 b와 같으면 true | 1 == 3 | false |
| a != b | a가 b와 같지 않으면 true | 1 != 3 | true |
| 연산자 | 내용 | 에제 | 결과 |
| !a | a가 true이면 false, false이면 true | !(3 < 5) | false |
| a || b | a와 b의 OR 연산. a와 b 모두 false인 경우에만 false | (3 > 5) || (1 == 1) | true |
| a && b | a와 b의 AND 연산. a와 b 모두 true인 경우에만 true | (3 < 5) && (1 == 1) | true |
| a ^ b | a와 b의 XOR 연산. a와 b가 서로 다를 때 true | (3 > 5)^ (1 == 1) | true |
비교 연산자와 논리 연산자를 복합하여 사용할 수 있습니다.
(age >= 20) && (age < 30) // 나이(int age)가 20대인 경우
(c >= 'A') && (c <= 'Z') // 문자(char c)가 대문자인 경우
(x >= 0) && (y >= 0) && (x <= 50) && (y <= 50) // (x, y)가 (0, 0)과 (50, 50)의 사각형 내에 있음
비교 연산과 논리 연산
public class LogicalOperator {
public static void main(String[] args) {
// 비교 연산
System.out.println('a' > 'b');
System.out.println(3 >= 2);
System.out.println(-1 < 0);
System.out.println(3.45 <= 2);
System.out.println(3 == 2);
System.out.println(3 != 2);
System.out.println(!(3 != 2));
// 비교 연산과 논리 연산 복합
System.out.println((3 > 2) && (3 > 4));
System.out.println((3 != 2) || (-1 > 0));
System.out.println((3 != 2) ^ (-1 > 0));
}
}
실행 결과
false
true
true
false
false
true
false
false
true
true
조건 연산
3개의 피연산자로 구성되어 삼항(ternary) 연산자라고도 하며 형식은 다음과 같습니다.
| condition ? opr2 : opr3 |
앞의 식에서 조건문(condition)이 true이면 위 식의 결과 값은 opr2의 값이 되고, false이면 opr3의 값이 됩니다.
int x = 5;
int y = 3;
int s = (x > y) ? 1 : -1; // x가 y보다 크기 때문에 1이 s에 대입된다.
조건 연산
public class TernaryOperator {
public static void main(String[] args) {
int a = 3, b = 5;
System.out.println("두 수의 차는 " + ((a > b) ? (a - b) : (b - a)));
}
}
실행 결과
두 수의 차는 2
비트 연산
비트끼리 AND, OR, XOR, NOT 연산을 하는 비트 논리 연산과, 비트를 오른쪽이나 왼쪽으로 이동시키는 비트 시프트 연산이 있습니다.
비트 개념
컴퓨터의 모든 정보는 0과 1 값만 가지는 2진수로 다루어지고 저장됩니다.
2진수의 한 자리를 비트(bit)라 부르며, 8개의 비트를 바이트(byte)라고 합니다.

비트 논리 연산
피연산자의 각 비트들끼리 이루어지는 AND, OR, XOR, NOT의 논리 연산입니다.

| 연산자 | 별칭 | 내용 |
| a & b | AND 연산 | 두 비트 모두 1이면 1, 그렇지 않으면 0 |
| a | b | OR 연산 | 두 비트 모두 0이면 0, 그렇지 않으면 1 |
| a ^ b | XOR 연산 | 두 비트가 다르면 1, 같으면 0 |
| ~ a | NOT 연산 | 1을 0으로, 0을 1로 변환 |
비트 논리 연산 활용 사례
어떤 비트가 1인지를 검사할 때 &(AND) 연산자를 이용합니다.
byte flag; // 8개의 각 비트는 8개의 센서 값을 가리킴
...
if (flag && 0b00001000 = 0) System.out.print("온도는 0도 이하");
else System.out.print("온도는 0도 이상");
결과
온도는 0도 이상
flag의 비트 3이 1인지를 판별하기 위해 flag와 이진수 00001000을 AND 연산합니다. 비트 3을 제외한 나머지 비트들의 AND 연산 결과는 모두 0이 됩니다. 만일 flag의 비트 3이 0이면 AND 연산 결과 모든 비트가 0이 되어, if문의 조건이 참이 됩니다.

비트 시프트 연산
3개의 연산자를 이용하여 새로운 비트를 오른쪽이나 왼쪽 끝에 삽입되면서 비트의 자리를 이동시키는 연산입니다.
저장 공간의 크기자 정해져 있으므로 시프트되는 방향에 따라 끝에 있는 비트는 사라지게 됩니다.
| 시프트 연산자 | 내용 |
| a >> b | a의 각 비트를 오른쪽으로 b번 시프트합니다. 최상위 비트의 빈자리는 시프트 전의 최상위 비트로 다시 채웁니다. 산술적 오른쪽 시프트라고 합니다. |
| a >>> b | a의 각 비트를 오른쪽으로 b번 시프트합니다. 최상위 비트의 빈자리는 항상 0으로 채웁니다. 논리적 오른쪽 시프트라고 합니다. |
| a << b | a의 각 비트를 왼쪽으로 b번 시프트한다. 최하위 비트의 빈자리는 항상 0으로 채웁니다. 산술적 왼쪽 시프트라고 합니다. |
시프트 연산의 피연산자는 byte, short, int, long, char 타입만 가능하고, float, double, boolean은 사용할 수 없습니다.
<< 연산자는 왼쪽 시프트 연산자로서 각 비트를 왼쪽으로 이동시키며, 오른쪽 끝에는 항상 비트 0이 삽입됩니다.
byte a = 5;
byte b = (byte) (a << 2); // a 값을 왼쪽으로 2비트 이동. b 값은 20
>>> 연산자는 비트를 오른쪽으로 이동시키며, 왼쪽 끝에는 항상 비트 0이 삽입됩니다
byte a = 20;
byte b = (byte) (a >>> 2); // a 값을 오른쪽으로 2비트 이동. b 값은 5
>> 연산자는 오른쪽 시프트 연산자이지만 >>> 와 달리 왼쪽 끝의 최상위 비트에는 시프트 이전의 최상위 비트가 그대로 삽입됩니다.
byte a = 20;
byte b = (byte) (a >> 2); // 변수 a 값을 오른쪽으로 2비트 이동. b 값은 5
byte c = (byte) 0xf8; // 0xf8는 -8을 16진수로 표현한 값
byte d = (byte) (c >> 2); // 변수 c를 오른쪽으로 2비트 이동, d 값은 0xfe가 됩니다.
// 0xfe는 십진수 -2
>>와 <<는 1비트 시프트할 때마다 나누가 2, 곱하기 2의 효과가 각각 나타납니다.

비트 논리 연산과 비트 시프트 연산
public class BitOperator {
public static void main(String[] args) {
short a = (short) 0x55ff;
short b = (short) 0x00ff;
// 비트 논리 연산
System.out.println("[비트 연산 결과]");
System.out.printf("%04x\n", (short) (a & b)); // 비트 AND
System.out.printf("%04x\n", (short) (a | b)); // 비트 OR
System.out.printf("%04x\n", (short) (a ^ b)); // 비트 XOR
System.out.printf("%04x\n", (short) (~a)); // 비트 NOT
byte c = 20; // 0x14
byte d = -8; // 0xf8
// 비트 시프트 연산
System.out.println("[시프트 연산 결과]");
System.out.println(c << 2); // c를 2비트 왼쪽 시프트
System.out.println(c >> 2); // c를 2비트 오른쪽 시프트. 0 삽입
System.out.println(d >> 2); // d를 2비트 오른쪽 시프트. 1 삽입
System.out.printf("%x\n", (d >>> 2)); // d를 2비트 오른쪽 시프트. 0 삽입
}
}
실행 결과
[비트 연산 결과]
00ff
55ff
5500
aa00
[시프트 연산 결과]
80
5
-2
3ffffffe