Java 입문 — 연산자
김영한의 자바 입문 강의 내용을 정리한 글이다.
1. 연산자 개요
+, -, *, /와 같이 계산을 수행하는 기호를 연산자(operator) 라 한다. 연산자가 작용하는 대상은 피연산자(operand) 다.
3 + 4 // 연산자: + 피연산자: 3, 4
a + b // 연산자: + 피연산자: a, b
자바가 제공하는 연산자를 분류하면 다음과 같다.
분류 연산자
산술 +, -, *, /, %
증감 ++, --
비교 ==, !=, >, <, >=, <=
논리 &&, ||, !
대입 =, +=, -=, *=, /=, %=
삼항 ? :
2. 산술 연산자
산술 연산자는 숫자를 계산하는 데 사용된다. +(더하기), -(빼기), *(곱하기), /(나누기), %(나머지) 다섯 가지다.
int a = 5 ;
int b = 2 ;
int sum = a + b; // 7
int diff = a - b; // 3
int multi = a * b; // 10
int div = a / b; // 2 (소수점 버림)
int mod = a % b; // 1
정수 나눗셈과 소수점 버림
5 / 2의 수학적 결과는 2.5지만, 자바에서 int끼리 나누면 결과도 int다. 소수점 이하는 버림(truncation)으로 처리된다. 반올림이 아니라 0 방향으로 잘라낸다 는 점이 중요하다.
System .out.println (7 / 2 ); // 3 (수학적으로는 3.5)
System .out.println (-7 / 2 ); // -3 (수학적으로는 -3.5, 0 방향으로 절사)
음수에서도 절댓값이 작아지는 방향으로 잘린다. 이것은 수학적 바닥 나눗셈(floor division)과 다르다. 실수 결과가 필요할 때는 한 쪽을 double로 캐스팅한다.
double result = (double ) 7 / 2 ; // 3.5
int / int → int (소수점 버림)
7 / 2
3
소수점 버림
double / int → double (소수점 유지)
(double)7 / 2
나머지 연산자 %
나머지 연산자는 나눗셈 후 남은 값을 돌려준다. 5 % 2는 몫 2, 나머지 1이므로 결과가 1이다. 실무와 알고리즘에서 자주 쓰이는 대표적인 용도는 다음과 같다.
홀짝 판별 : n % 2 == 0이면 짝수, n % 2 != 0이면 홀수
순환 인덱스 : 배열 끝에 도달하면 처음으로 돌아오도록 index % length
자릿수 분리 : n % 10으로 마지막 자릿수 추출
int n = 17 ;
System .out.println (n % 2 == 0 ? "짝수" : "홀수" ); // 홀수
System .out.println (n % 10 ); // 7 (마지막 자리)
0으로 나누기
정수를 0으로 나누면 ArithmeticException: / by zero 예외가 발생하고 프로그램이 종료된다. 수학적으로도 정의되지 않는 연산이다.
Exception in thread "main" java.lang.ArithmeticException: / by zero
3. 문자열 더하기
자바는 문자열(String)에도 + 연산자를 사용할 수 있다. 두 문자열을 이어 붙이는 연결(concatenation) 연산이다.
String result1 = "hello " + "world" ; // "hello world"
String s1 = "string1" ;
String s2 = "string2" ;
String result2 = s1 + s2; // "string1string2"
문자열과 숫자를 더하면 숫자가 문자열로 자동 변환된 뒤 연결된다.
String result3 = "a + b = " + 10 ; // "a + b = 10"
int num = 20 ;
String str = "a + b = " ;
String result4 = str + num; // "a + b = 20"
계산 과정을 단계별로 따라가면 이렇다.
"a + b = " + 10 (int )
"a + b = " + "10" // int → String 자동 변환
"a + b = 10" // 문자열 연결
String에 어떤 타입을 더해도 그 타입을 문자열로 변환한 뒤 연결한다. 이것이 자바의 규칙이다.
4. 연산자 우선순위
수학에서 1 + 2 * 3의 결과는 7이다. 곱셈이 덧셈보다 우선순위가 높기 때문이다. 자바도 동일한 규칙을 따른다.
int sum1 = 1 + 2 * 3 ; // 7 (곱셈 먼저)
int sum2 = (1 + 2 ) * 3 ; // 9 (괄호 먼저)
int sum3 = 2 * 2 + 3 * 3 ; // 13 = (2*2) + (3*3) = 4 + 9
int sum4 = (2 * 2 ) + (3 * 3 ); // 13 (sum3과 동일, 명시적 표현)
자바 연산자 우선순위를 높은 순서부터 정리하면 다음과 같다.
순위 분류 연산자
1 괄호 ()
2 단항 ++, --, !, ~, (type)
3 산술 (곱·나눗셈) *, /, %
4 산술 (덧·뺄셈) +, -
5 Shift <<, >>, >>>
6 비교 <, <=, >, >=, instanceof
7 등식 ==, !=
8 비트 &, ^, |
9 논리 &&, ||
10 삼항 ? :
11 대입 =, +=, -=, *=, /=, %=
실무 접근법
실무 개발자들은 우선순위 표를 외우지 않는다. 두 가지 원칙만 따른다.
상식 수준에서 판단한다. *가 +보다 우선이라는 것은 수학 상식이다. 대입 연산자 =가 가장 낮다는 것도 자연스럽다.
애매하면 괄호를 쓴다. 코드를 읽는 사람이 우선순위를 고민해야 한다면, 괄호로 의도를 명시하는 것이 맞다.
// 의도가 불분명한 코드
int x = a + b * c - d / e;
// 의도가 명확한 코드
int x = (a + (b * c)) - (d / e);
코드는 짧을수록 좋은 것이 아니다. 읽는 사람이 이해하기 쉬울수록 좋다.
5. 증감 연산자
증감 연산자는 변수의 값을 1씩 증가(++)하거나 감소(--)시키는 단축 표현이다. 루프 카운터처럼 값을 1씩 올리는 상황이 프로그래밍에서 매우 자주 등장하기 때문에 이런 편의 문법을 제공한다.
int a = 0 ;
a = a + 1 ; // 기존 방식: a = 1
++a; // 동일한 효과: a = 2
a++; // 동일한 효과: a = 3
전위(Prefix) vs 후위(Postfix)
증감 연산자를 다른 연산과 함께 쓸 때 위치가 결과에 영향을 미친다.
++a 전위 : 증감을 먼저 수행한 뒤 나머지 연산
a++ 후위 : 나머지 연산을 먼저 수행한 뒤 증감
전위(++a): 증가 먼저, 대입 나중
a
1
→ ++a 실행 →
a
2
→ b에 대입 →
b
2
a=2, b=2
후위(a++): 대입 먼저, 증가 나중
a
1
→ b에 대입 →
b
1
→ a++ 실행 →
a
2
a=2, b=1
b = ++a → a 먼저 증가 후 b에 대입 → a=2, b=2
b = a++ → b에 대입 후 a 증가 → a=2, b=1
int a = 1 ;
int b = 0 ;
b = ++a; // a를 먼저 2로 증가 → b에 2 대입 → a=2, b=2
System .out.println ("a = " + a + ", b = " + b); // a = 2, b = 2
a = 1 ; b = 0 ;
b = a++; // b에 현재 a(1) 대입 → a를 2로 증가 → a=2, b=1
System .out.println ("a = " + a + ", b = " + b); // a = 2, b = 1
전위·후위 구분이 필요한 코드는 가독성을 해친다. 실무에서는 증감 연산자를 단독으로 사용하고, 대입과 섞는 패턴은 피하는 것이 권장된다.
6. 비교 연산자
비교 연산자는 두 값을 비교해 true 또는 false를 반환한다. 조건문에서 가장 많이 사용된다.
연산자 의미 예시 결과
==같다 2 == 3false
!=다르다 2 != 3true
>크다 2 > 3false
<작다 2 < 3true
>=크거나 같다 3 >= 3true
<=작거나 같다 2 <= 3true
int a = 2 ;
int b = 3 ;
System .out.println (a == b); // false
System .out.println (a != b); // true
System .out.println (a > b); // false
System .out.println (a < b); // true
System .out.println (a >= b); // false
System .out.println (a <= b); // true
boolean result = a == b; // false를 변수에 저장
=와 ==는 전혀 다르다. =는 값을 저장하는 대입 연산자, ==는 두 값이 같은지 확인하는 비교 연산자다.
문자열 비교
문자열을 비교할 때는 == 대신 .equals() 메서드를 사용해야 한다. ==로 문자열을 비교하면 값이 아닌 객체의 주소를 비교하게 되어 기대와 다른 결과가 나올 수 있다. String이 참조 타입이기 때문이다.
String str1 = "문자열1" ;
String str2 = "문자열2" ;
boolean result1 = "hello" .equals ("hello" ); // true
boolean result2 = str1.equals ("문자열1" ); // true
boolean result3 = str1.equals (str2); // false
7. 논리 연산자
논리 연산자는 boolean 값을 조합하는 데 사용된다.
연산자 의미 설명
&&AND (그리고) 둘 다 true일 때만 true
||OR (또는) 하나라도 true이면 true
!NOT (부정) true는 false로, false는 true로
&& (AND) 진리표
A
B
A && B
true
true
true
true
false
false
false
false
false
|| (OR) 진리표
A
B
A || B
true
true
true
true
false
true
false
false
false
System .out.println (true && true ); // true
System .out.println (true && false ); // false
System .out.println (false && false ); // false
System .out.println (true || true ); // true
System .out.println (true || false ); // true
System .out.println (false || false ); // false
System .out.println (!true ); // false
System .out.println (!false ); // true
논리 연산자 활용
변수 a가 10보다 크고 20보다 작은지 확인하는 코드다.
int a = 15 ;
boolean result = a > 10 && a < 20 ; // true
// 범위 표현 — 가독성 있는 형태
boolean result2 = 10 < a && a < 20 ; // 동일한 결과
단락 평가 (Short-Circuit Evaluation)
&&와 ||는 단락 평가를 수행한다. 첫 번째 피연산자만으로 결과가 확정되면 두 번째 피연산자를 아예 평가하지 않는다.
&&: 첫 번째가 false이면 두 번째를 보지 않는다. (어차피 결과가 false)
||: 첫 번째가 true이면 두 번째를 보지 않는다. (어차피 결과가 true)
&& 단락 평가: 첫 번째가 false이면 두 번째는 평가하지 않음
false
&&
평가 안 함
→
false
|| 단락 평가: 첫 번째가 true이면 두 번째는 평가하지 않음
true
||
평가 안 함
→
true
이 성질은 null 체크와 함께 자주 활용된다. s가 null이면 s.equals()를 호출하지 않으므로 NullPointerException이 발생하지 않는다.
String s = null ;
if (s != null && s.equals ("hello" )) {
System .out.println ("일치" );
}
// s가 null이므로 첫 번째 조건이 false → 두 번째 조건 평가 안 함 → 안전
8. 대입 연산자
대입 연산자 =는 오른쪽 값을 왼쪽 변수에 저장한다.
복합 대입 연산자
산술 연산과 대입을 한 번에 축약한 것이 복합 대입 연산자다.
연산자 풀어 쓴 형태
i += 3i = i + 3
i -= 2i = i - 2
i *= 4i = i * 4
i /= 3i = i / 3
i %= 5i = i % 5
int a = 5 ;
a += 3 ; // 8 (5 + 3)
a -= 2 ; // 6 (8 - 2)
a *= 4 ; // 24 (6 * 4)
a /= 3 ; // 8 (24 / 3)
a %= 5 ; // 3 (8 % 5)
System .out.println (a); // 3
복합 대입 연산자는 가독성 외에 한 가지 중요한 특성이 있다. 연산 결과를 왼쪽 변수 타입으로 자동 캐스팅 한다.
byte b = 10 ;
b += 5 ; // 컴파일 가능 (자동 캐스팅)
b = b + 5 ; // 컴파일 오류: int → byte 명시적 캐스팅 필요
b + 5는 자바 내부에서 int로 계산된 뒤 다시 byte에 넣으려 하기 때문에 오류가 발생한다. +=는 이 과정을 자동으로 처리한다.
9. 삼항 연산자
삼항 연산자는 조건에 따라 두 값 중 하나를 선택하는 연산자다. 피연산자가 세 개라서 삼항(三項)이다.
조건식 ? 참일 때 값 : 거짓일 때 값
int a = 10 ;
int b = 20 ;
int max = a > b ? a : b; // 20 (b가 더 크므로)
if-else로 풀어 쓰면 다음과 같다.
int max;
if (a > b) {
max = a;
} else {
max = b;
}
단순한 조건 분기에서 삼항 연산자를 쓰면 코드가 짧고 명확해진다. 단, 조건이 복잡하거나 중첩이 필요한 경우에는 if-else가 훨씬 읽기 좋다.
// 중첩 삼항은 읽기 어렵다 — 실무에서 지양
String grade = score >= 90 ? "A" : score >= 80 ? "B" : score >= 70 ? "C" : "F" ;
// if-else가 더 명확하다
String grade;
if (score >= 90 ) grade = "A" ;
else if (score >= 80 ) grade = "B" ;
else if (score >= 70 ) grade = "C" ;
else grade = "F" ;
10. 연습 — int와 평균
세 정수의 합과 평균을 구하는 코드다. int끼리 나누면 소수점이 버려진다는 점을 확인할 수 있다.
int num1 = 10 ;
int num2 = 20 ;
int num3 = 30 ;
int sum = num1 + num2 + num3; // 60
int average = sum / 3 ; // 20 (소수점 버림)
System .out.println (sum); // 60
System .out.println (average); // 20
double로 바꾸면 소수점이 살아난다.
double val1 = 1.5 ;
double val2 = 2.5 ;
double val3 = 3.5 ;
double sum = val1 + val2 + val3; // 7.5
double avg = sum / 3 ; // 2.5
System .out.println (sum); // 7.5
System .out.println (avg); // 2.5