자바 연산자 정리 — 우선순위, 오버플로우, NaN과 Infinity
연산(operations)은 데이터를 처리하여 결과를 산출하는 것이고, 연산자(operator)는 연산에 사용되는 표시나 기호이며, 피연산자(operand)는 연산되는 데이터입니다. 연산자와 피연산자를 이용하여 연산의 과정을 기술한 것을 연산식(expressions)이라고 합니다.
이 글은 2021년 8월 기준 기록입니다.
연산자는 종류별로 자리 수가 정해져 있다
연산자를 종류별로 정리하면 다음과 같습니다.
| 연산자 종류 | 연산자 | 피연산자의 수 | 산출값 | 기능 설명 |
|---|---|---|---|---|
| 산술 | + - * / % |
이항 | 숫자 | 사칙연산 및 나머지 계산 |
| 부호 | + - |
단항 | 숫자 | 음수와 양수의 부호 |
| 문자열 | + |
이항 | 문자열 | 두 문자열을 연결 |
| 대입 | = += -= *= /= %= ^= |= <<= >>= >>>= |
이항 | 다양 | 우변의 값을 좌변의 변수에 대입 |
| 증감 | ++ -- |
단항 | 숫자 | 1만큼 증가/감소 |
| 비교 | == != > < >= <= instanceof |
이항 | boolean | 값의 비교 |
| 논리 | ! & | && || |
단항, 이항 | boolean | 논리적 NOT, AND, OR 연산 |
| 조건 | (조건식)?A:B |
삼항 | 다양 | 조건식에 따라 A 또는 B 중 선택 |
| 비트 | ~ & | ^ |
단항, 이항 | 숫자, boolean | 비트 NOT, AND, OR, XOR 연산 |
| 쉬프트 | >> << >>> |
이항 | 숫자 | 비트를 좌측/우측으로 밀어서 이동 |
우선순위는 네 줄로 요약된다
연산자마다 연산 방향과 우선순위가 정해져 있습니다.
- 단항, 이항, 삼항 연산자 순으로 우선순위를 가집니다.
- 산술, 비교, 논리, 대입 연산자 순으로 우선순위를 가집니다.
- 단항과 대입 연산자를 제외한 모든 연산의 방향은 왼쪽에서 오른쪽입니다.
- 복잡한 연산식에는 괄호
()를 사용해서 우선순위를 정해 줍니다.
단항 연산자 — 위치가 의미를 바꾼다
부호 연산자(+, -)는 양수 및 음수를 표시합니다. 산출 타입은 int 타입이 됩니다.
증감 연산자(++, --)는 변수의 값을 1 증가시키거나 감소시킵니다. 이 연산자의 핵심은 피연산자의 앞에 붙느냐 뒤에 붙느냐에 따라 의미가 달라진다는 점입니다. 앞에 붙으면 다른 연산을 수행하기 전에 피연산자의 값을 변화시키고, 뒤에 붙으면 다른 연산을 수행한 후에 값을 변화시킵니다.
성능 면에서는 차이가 없습니다. ++i와 i=i+1은 동일한 바이트 코드로 컴파일되므로 연산 속도는 같습니다.
논리 부정 연산자(!)는 true를 false로, false를 true로 변경합니다.
비트 반전 연산자(~)는 피연산자를 2진수로 표현했을 때 비트값 0을 1로, 1을 0으로 반전합니다. 이때 부호 비트인 최상위 비트까지 포함해서 반전되므로 부호가 반대인 값이 산출됩니다. 산출 타입은 int 타입입니다.
산술 연산자에서 조심할 것은 결과 타입과 0이다
산술 연산자(+, -, *, /, %)는 더하기, 빼기, 곱하기, 나누기, 나머지 연산을 수행합니다.
먼저 결과 타입입니다. 기본적으로 정수 타입 연산은 int로 결과가 나옵니다. char 간 연산도 int로 나오기 때문에, 문자를 얻으려면 (char)로 캐스팅해 주어야 합니다.
그리고 오버플로우 탐지가 필요합니다. 연산 후의 산출값이 산출 타입으로 표현 가능한지 확인해야 쓰레기값을 피할 수 있습니다. 같은 맥락에서, 정확한 연산이 필요할 때는 부동소수점 타입을 사용하지 않고 정수를 쓰는 편이 좋습니다.
0으로 나누면 예외가 날 수도, Infinity가 나올 수도 있다
/ 또는 % 연산자에서 나누는 수로 0을 사용할 수는 없습니다. 그런데 정수 0으로 나눌 때와 실수 0.0으로 나눌 때의 결과가 다릅니다.
5 / 0 // 컴파일은 정상적으로 되지만 실행 시 ArithmeticException(예외) 발생
5 % 0 // 컴파일은 정상적으로 되지만 실행 시 ArithmeticException(예외) 발생
실수 타입인 0.0 또는 0.0f로 나누면 예외가 발생하지 않고 대신 특수한 값을 가집니다.
5 / 0.0 // Infinity
5 % 0.0 // NaN
이쪽이 오히려 더 위험합니다. 예외는 즉시 멈추지만, Infinity(무한대)나 NaN(Not a Number)은 조용히 전파됩니다.
Infinity나 NaN이 나오면 어떤 수와 연산하더라도 Infinity와 NaN이 산출되어 데이터가 엉망이 됩니다. 그래서
Double.isInfinite()와 Double.isNaN() 메소드로 검사해서 처리해야 합니다. 두 메소드는 true, false로 값을 산출합니다.
특히 부동소수점을 입력받을 때는 반드시 NaN 검사를 해야 합니다. 입력값이 NaN인지 확인하여, NaN일 때는 연산이 수행되지 않도록 처리합니다.
문자열 비교에 ==를 쓰면 주소를 비교하게 된다
문자열 연결 연산자(+)부터 짚고 갑니다. 피연산자 중 한쪽이 문자열이면 + 연산자는 문자열 연결 연산자로 사용됩니다.
비교 연산자(<, <=, >, >=, ==, !=)는 대소 또는 동등 비교를 통해 boolean 값을 산출합니다. char 타입의 경우 유니코드 값으로 비교 연산을 수행하고, float과 double의 경우 근사값 표현 범위 차이 때문에 동등 비교를 할 때 강제 타입 변환이 필요합니다.
String 타입에서는 이야기가 달라집니다. String 타입의 문자열을 비교할 때에는 대소 연산자를 사용할 수 없고, 동등 비교 연산자는 사용할 수 있습니다. 그런데 그 동등 비교는 문자열이 같은지 다른지를 비교하는 용도가 아닙니다. String은 참조 타입이므로 객체 주소 참조를 통한 비교를 하고, 같은 문자열이어도 주소가 다르면 다르게 인식됩니다. 따라서 문자열 자체만 비교하고 싶다면 equals() 메소드를 사용해야 합니다.
논리 연산자와 비트 연산자는 대상이 다를 뿐 규칙은 같다
논리 연산자(&&, ||, &, |, ^, !)의 규칙은 다음과 같습니다.
- AND — 논리곱(
&&,&) — 피연산자 모두가true일 경우에만 결과가true입니다. - OR — 논리합(
||,|) — 피연산자 중 하나만true이면 결과는true입니다. - XOR — 배타적 논리합(
^) — 피연산자 하나가true이고 다른 하나가false일 경우에만 결과가true입니다. - NOT — 논리 부정(
!) — 피연산자의 논리값을 바꿉니다.
비트 연산자(&, |, ^, ~, <<, >>, >>>)는 데이터를 비트 단위로 연산합니다. 크게 둘로 나뉩니다. 비트 논리 연산은 0과 1에 대한 논리 연산으로, 위의 논리 연산자와 동일하게 작동합니다. 비트 이동 연산은 데이터의 비트를 좌측 또는 우측으로 밀어서 이동시키는 연산입니다.
대입 연산자는 오른쪽 피연산자의 값을 왼쪽 피연산자인 변수에 저장합니다.
삼항 연산자는 조건을 한 줄로 접는다
삼항 연산자는 세 개의 피연산자를 필요로 하는 연산자로, 조건식 ? 참 : 거짓 형태를 가집니다.
연산자를 외우는 일보다 중요한 것은 두 가지입니다. 결과가 어떤 타입으로 산출되는지, 그리고 그 결과가 표현 범위를 벗어나거나 NaN이 되지는 않는지입니다.
'IT·테크 > 개발' 카테고리의 다른 글
| Git 기본기 — 스테이징부터 되돌리기와 브랜치까지 (0) | 2026.07.22 |
|---|---|
| 자바 참조 타입 — 스택과 힙, 배열, 열거 타입 정리 (0) | 2026.07.21 |
| 자바 변수와 타입 — 기본 타입 8개와 타입 변환 규칙 (0) | 2026.07.20 |
| 자바 시작하기 — JVM과 바이트 코드, 그리고 개발 환경 (0) | 2026.07.19 |