ch3_연산자
통합 문서입니다.
1. 문제
문제
ch3 범위(산술/비교/논리/대입/비트/시프트/삼항 연산자) 문제입니다.
A. 기초 문제
- 두 정수를 입력받아 합, 차, 곱, 몫, 나머지를 출력하시오.
- 세 점수를 입력받아 평균을 구하고, 평균이 60 이상이면
PASS, 아니면FAIL을 출력하시오. - 정수 하나를 입력받아 짝수/홀수를 판별하시오.
- 나이를 입력받아 20 이상 65 미만이면
일반 요금, 아니면우대 요금을 출력하시오.
B. 비교/논리 연산
- 아이디/비밀번호가 모두 일치할 때만 로그인 성공 메시지를 출력하시오.
- 정수 3개를 입력받아 최댓값/최솟값을 구하시오(
Math.max/min사용 금지). - 세 변의 길이를 받아 삼각형 성립 여부를 판별하시오.
- 윤년 판별식을 논리 연산자로 구현하시오.
C. 실수/정밀도
0.1 + 0.2 == 0.3비교 결과를 출력하고, 왜 그런 결과가 나오는지 설명하시오.- 허용 오차(EPSILON) 기반 실수 비교 함수를 작성하시오.
- 정수 나눗셈과 실수 나눗셈 결과가 달라지는 예제를 3개 작성하시오.
D. 비트/시프트 연산
- 정수 하나를 입력받아 다음을 출력하시오.
- 2진수 문자열
<< 1,>> 1,>>> 1결과
- 비트 마스크를 사용해 권한 플래그(
READ,WRITE,EXECUTE)를 구현하시오. - RGB 정수값(0xRRGGBB)에서 R, G, B를 분리하는 코드를 작성하시오.
- 음수 시프트에서
>>와>>>결과 차이를 예제로 설명하시오.
E. 대입/증감/삼항
- 전위/후위 증감 연산 결과가 다른 코드를 5개 작성하고 결과를 예측한 뒤 검증하시오.
short s = 1; s += 1;는 되는데s = s + 1;가 안 되는 이유를 설명하시오.- 중첩 삼항 연산자를
if-else로 리팩터링하는 연습 코드를 작성하시오. - 복합 대입 연산(
+=,*=)이 포함된 식에서 타입 변화를 추적하시오.
F. 디버깅 문제
다음 코드의 문제점을 찾고 수정하시오.
String role = new String("ADMIN");
if (role == "ADMIN") {
System.out.println("관리자");
}
int total = 0;
for (int i = 1; i <= 1000000; i++) {
total += i;
}
System.out.println(total);
수정 시 고려할 것:
- 문자열 비교 방식
- 정수 오버플로우 가능성
G. 챌린지
- 계산기 프로그램을 작성하시오.
- 입력: 피연산자 2개 + 연산자(
+,-,*,/,%) - 0 나눗셈과 잘못된 연산자 처리 포함
- 입력: 피연산자 2개 + 연산자(
- 비트 연산만 사용해 정수의 홀짝 판별, 절댓값 근사 함수를 작성하시오.
- 로그 시스템의 상태 코드를 비트 플래그로 설계하고, 조합/해제/검사 메서드를 구현하시오.
제출 체크리스트
- 연산자 우선순위가 헷갈리는 식에 괄호를 사용했는가?
- 문자열 비교에
equals를 사용했는가? - 정수 오버플로우 가능성을 점검했는가?
&&/||와&/|의 차이를 코드에서 명확히 구분했는가?
2. 연산자
연산자
학습 목표
- Java 연산자 체계를 “문법 목록”이 아니라 “평가 규칙” 관점으로 설명할 수 있다.
- 산술/비교/논리/비트/시프트/대입/삼항 연산자의 동작 차이를 이해한다.
- 오버플로우, 단락 평가, 복합 대입의 숨은 캐스팅 등 실무 버그 포인트를 피할 수 있다.
1. 연산자란
연산자는 피연산자(operand)에 규칙을 적용해 결과를 만드는 문법 요소다.
실무에서는 연산자 자체보다 평가 순서, 타입 승격, 부수 효과(side effect)를 이해하는 것이 중요하다.
2. 산술 연산자 (+, -, *, /, %)
2.1 기본 동작
int a = 7;
int b = 3;
System.out.println(a + b); // 10
System.out.println(a - b); // 4
System.out.println(a * b); // 21
System.out.println(a / b); // 2
System.out.println(a % b); // 1
정수 나눗셈은 소수부를 버린다.
2.2 0으로 나누기
정수:
int x = 10 / 0; // ArithmeticException
실수:
double x = 10.0 / 0.0; // Infinity
double y = 0.0 / 0.0; // NaN
정수/실수는 에러 처리 방식이 다르므로 구분해야 한다.
2.3 오버플로우
int max = Integer.MAX_VALUE;
System.out.println(max + 1); // 음수로 래핑
Java 정수 오버플로우는 예외 없이 wrap-around 된다.
3. 증감 연산자 (++, --)
3.1 전위/후위 차이
int i = 5;
int a = ++i; // i를 먼저 6으로 만들고 a=6
int b = i++; // b=6 대입 후 i=7
3.2 실무 권장
복잡한 식 안에서 i++를 섞으면 가독성이 급격히 떨어진다.
// 지양
arr[i++] = arr[++i] + i--;
증감과 계산은 분리하는 편이 안전하다.
4. 비교 연산자 (==, !=, >, <, >=, <=)
비교 결과는 항상 boolean이다.
int age = 20;
boolean adult = age >= 19;
4.1 실수 비교 주의
double a = 0.1 + 0.2;
System.out.println(a == 0.3); // false 가능
실수는 오차가 있으므로 허용 오차 기반 비교를 사용한다.
boolean same = Math.abs(a - 0.3) < 1e-12;
5. 동등성 비교: == vs equals
5.1 primitive
==는 값 비교다.
int x = 10;
int y = 10;
System.out.println(x == y); // true
5.2 reference
==는 참조 동일성(같은 객체인가)을 비교한다.
String s1 = new String("java");
String s2 = new String("java");
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true
문자열/값 객체의 내용 비교는 equals가 기본이다.
6. 논리 연산자와 단락 평가
6.1 &&, ||, !
boolean a = true;
boolean b = false;
System.out.println(a && b); // false
System.out.println(a || b); // true
System.out.println(!a); // false
6.2 단락 평가 (Short-circuit)
A && B: A가 false면 B 평가 안 함A || B: A가 true면 B 평가 안 함
if (obj != null && obj.isValid()) {
// obj null 체크 후 접근
}
이 패턴이 NPE를 줄이는 핵심이다.
6.3 &, |와의 차이
&, |는 boolean에도 쓸 수 있지만 양쪽을 항상 평가한다.
if (obj != null & obj.isValid()) { // 지양: null이면 NPE 위험
}
조건식에서는 보통 &&, ||를 사용한다.
&&와 ||에서 오른쪽 피연산자를 생략 평가하는 조건을 시각화한 그림이다.
7. 비트 연산자 (&, |, ^, ~)
정수 비트를 직접 다룬다.
int a = 0b1100;
int b = 0b1010;
System.out.println(a & b); // 0b1000
System.out.println(a | b); // 0b1110
System.out.println(a ^ b); // 0b0110
System.out.println(~a); // 비트 반전
용도:
- 플래그 마스킹
- 네트워크/파일 포맷 파싱
- 성능 민감한 로우레벨 처리
8. 시프트 연산자 (<<, >>, >>>)
8.1 왼쪽 시프트 <<
비트를 왼쪽으로 밀고 빈칸을 0으로 채운다.
int x = 3; // 0011
int y = x << 2; // 1100 -> 12
8.2 부호 유지 오른쪽 시프트 >>
부호 비트를 유지하며 오른쪽 이동한다.
int x = -8;
int y = x >> 1; // -4
8.3 부호 없는 오른쪽 시프트 >>>
왼쪽을 0으로 채운다.
int x = -8;
int y = x >>> 1; // 큰 양수
암호화, 해시, 비트 포맷 처리에서 중요하다.
<<, >>, >>>가 비트를 어떻게 이동시키는지 예제로 정리한 그림이다.
9. 대입/복합 대입 연산자
기본 대입:
int n = 10;
복합 대입:
n += 5;
n *= 2;
주의 포인트:
short s = 1;
s += 1; // 가능 (내부 캐스팅)
// s = s + 1; // 컴파일 오류 (int 결과)
복합 대입에는 숨은 캐스팅 규칙이 있어 결과를 반드시 확인해야 한다.
10. 삼항 연산자 (조건 ? 값1 : 값2)
단순 분기값 선택에 유용하다.
int score = 85;
String grade = score >= 80 ? "PASS" : "FAIL";
복잡한 삼항 중첩은 가독성을 해치므로 if로 바꾸는 것이 낫다.
11. 우선순위와 결합 방향
우선순위를 전부 암기하는 것보다 원칙을 지키는 게 좋다.
- 애매하면 괄호를 쓴다.
- 부수 효과가 있는 연산(
++,--, 대입)을 식에서 분리한다. - 한 줄 식이 길어지면 중간 변수를 도입한다.
예:
// 지양
boolean ok = a + b * c > d && e != 0 || f < g;
// 권장
int calc = a + (b * c);
boolean left = calc > d;
boolean right = e != 0;
boolean ok = (left && right) || (f < g);
12. 자주 나오는 실무 버그
- 문자열 비교를
==로 수행 - 정수 나눗셈 결과를 실수라고 착각
&&대신&를 써서 불필요 평가/NPE 발생- 오버플로우를 고려하지 않은 카운터/금액 연산
- 복합 대입의 자동 캐스팅을 모르고 타입 버그 발생
13. 정리
- 연산자의 핵심은 문법보다 평가 규칙과 타입 규칙이다.
- 단락 평가, 동등성 비교, 오버플로우 동작을 정확히 아는 것이 버그 예방에 직접 연결된다.
- 읽기 쉬운 식을 작성하는 습관이 유지보수성과 안정성을 결정한다.