03. 연산자와 표현식
연산자는 값(피연산자)을 받아 새로운 값을 만드는 기호입니다. Java 의 연산자는 C/C++ 에서 유래해 익숙한 모양이지만, **객체 비교(`==` vs `.equals()`)** 와 **정수/실수 나눗셈** 같은 함정이 있습니다. 이 단원에서 정리합니다.
이 강의에서 배우는 것
- 1산술·비교·논리·비트·삼항·증감 연산자를 구분해 사용한다
- 2`String` 결합 시 `+` 의 좌→우 평가 규칙을 이해한다
- 3`==` 와 `.equals()` 의 차이를 명확히 안다
- 4짧은 회로 평가(short-circuit `&&` / `||`) 가 무엇인지 이해한다
소개
연산자는 값(피연산자)을 받아 새로운 값을 만드는 기호입니다. Java 의 연산자는 C/C++ 에서 유래해 익숙한 모양이지만, **객체 비교(`==` vs `.equals()`)** 와 **정수/실수 나눗셈** 같은 함정이 있습니다. 이 단원에서 정리합니다.
핵심 개념
1) 산술 / 비교 / 논리
int a = 10, b = 3;
System.out.println(a + b); // 13
System.out.println(a / b); // 3 (정수 나눗셈!)
System.out.println(a % b); // 1
System.out.println(a > b); // true
System.out.println(a == 10 && b > 0); // true2) 증감 연산자
int x = 5;
System.out.println(x++); // 5 (사용 후 증가)
System.out.println(++x); // 7 (증가 후 사용)`x++` 와 `++x` 는 결과 값이 다릅니다. 식 안에 섞어 쓰면 가독성이 떨어지니 주의하세요.
3) 삼항 연산자
int score = 75;
String result = (score >= 60) ? "합격" : "불합격";`if/else` 의 짧은 형태입니다. 한 줄로 값을 정할 때 유용합니다.
4) `==` vs `.equals()`
String a = "hello";
String b = new String("hello");
System.out.println(a == b); // false (참조 다름)
System.out.println(a.equals(b)); // true (내용 같음)**객체(특히 String/Integer/리스트 등)는 항상 `.equals()`** 로 비교하세요. `==` 은 primitive 끼리 또는 참조 동일성 확인용입니다.
5) 비트 연산자
int mask = 0b1010;
int val = 0b1100;
System.out.println(mask & val); // 8 (AND)
System.out.println(mask | val); // 14 (OR)
System.out.println(mask ^ val); // 6 (XOR)
System.out.println(mask << 1); // 20 (왼쪽 시프트)플래그 처리·해시·암호화 같은 곳에서 만나게 됩니다.
핵심 예제
예제 1 — `Arithmetic.java` : 산술과 나눗셈 함정
public class Arithmetic {
public static void main(String[] args) {
int a = 17, b = 5;
System.out.println(a + b);
System.out.println(a - b);
System.out.println(a * b);
System.out.println(a / b); // 정수 나눗셈
System.out.println(a % b);
System.out.println((double) a / b); // 실수 나눗셈
}
}**실행 결과**
22
12
85
3
2
3.4**메모:** `int / int` 는 항상 정수입니다. 실수가 필요하면 한쪽을 `double` 로 캐스팅하세요.
예제 2 — `LogicAndTernary.java` : 비교·논리·삼항
public class LogicAndTernary {
public static void main(String[] args) {
int score = 75;
boolean passed = score >= 60;
System.out.println("합격? " + passed);
String grade = (score >= 90) ? "A"
: (score >= 80) ? "B"
: (score >= 70) ? "C"
: (score >= 60) ? "D"
: "F";
System.out.println("등급: " + grade);
boolean ok = score > 0 && score <= 100;
System.out.println("유효 범위? " + ok);
}
}**실행 결과**
합격? true
등급: C
유효 범위? true**메모:** `&&` 와 `||` 는 **단락 평가(short-circuit)** 입니다. `a != null && a.length() > 0` 처럼 안전한 null 체크가 가능합니다.
예제 3 — `EqualsVsEqEq.java` : 참조 비교 vs 내용 비교
public class EqualsVsEqEq {
public static void main(String[] args) {
String a = "Java";
String b = "Java";
String c = new String("Java");
System.out.println("a == b : " + (a == b));
System.out.println("a == c : " + (a == c));
System.out.println("a.equals(c) : " + a.equals(c));
Integer x = 100;
Integer y = 100;
Integer z = 200;
Integer w = 200;
System.out.println("100==100? " + (x == y)); // 캐시로 true
System.out.println("200==200? " + (z == w)); // 캐시 밖, false
System.out.println("equals : " + z.equals(w));
}
}**실행 결과**
a == b : true
a == c : false
a.equals(c) : true
100==100? true
200==200? false
equals : true**메모:** `Integer` 는 `-128 ~ 127` 만 캐시되어 `==` 가 우연히 true 가 됩니다. **객체는 항상 `.equals()`**.
예제 4 — `Bitwise.java` : 비트 연산
public class Bitwise {
public static void main(String[] args) {
int a = 0b1010;
int b = 0b1100;
System.out.printf("a & b = %d (%s)%n", a & b, Integer.toBinaryString(a & b));
System.out.printf("a | b = %d (%s)%n", a | b, Integer.toBinaryString(a | b));
System.out.printf("a ^ b = %d (%s)%n", a ^ b, Integer.toBinaryString(a ^ b));
System.out.printf("~a = %d%n", ~a);
System.out.printf("a<<1 = %d%n", a << 1);
System.out.printf("a>>1 = %d%n", a >> 1);
}
}**실행 결과**
a & b = 8 (1000)
a | b = 14 (1110)
a ^ b = 6 (110)
~a = -11
a<<1 = 20
a>>1 = 5**메모:** `~a` 는 `-(a+1)` 입니다. 2의 보수 표현 때문에 그렇습니다.
전체 예제 코드 (src/)
src/Arithmetic.java
public class Arithmetic {
public static void main(String[] args) {
int a = 17, b = 5;
System.out.println(a + b);
System.out.println(a - b);
System.out.println(a * b);
System.out.println(a / b);
System.out.println(a % b);
System.out.println((double) a / b);
}
}
src/Bitwise.java
public class Bitwise {
public static void main(String[] args) {
int a = 0b1010;
int b = 0b1100;
System.out.printf("a & b = %d (%s)%n", a & b, Integer.toBinaryString(a & b));
System.out.printf("a | b = %d (%s)%n", a | b, Integer.toBinaryString(a | b));
System.out.printf("a ^ b = %d (%s)%n", a ^ b, Integer.toBinaryString(a ^ b));
System.out.printf("~a = %d%n", ~a);
System.out.printf("a<<1 = %d%n", a << 1);
System.out.printf("a>>1 = %d%n", a >> 1);
}
}
src/EqualsVsEqEq.java
public class EqualsVsEqEq {
public static void main(String[] args) {
String a = "Java";
String b = "Java";
String c = new String("Java");
System.out.println("a == b : " + (a == b));
System.out.println("a == c : " + (a == c));
System.out.println("a.equals(c) : " + a.equals(c));
Integer x = 100;
Integer y = 100;
Integer z = 200;
Integer w = 200;
System.out.println("100==100? " + (x == y));
System.out.println("200==200? " + (z == w));
System.out.println("equals : " + z.equals(w));
}
}
src/LogicAndTernary.java
public class LogicAndTernary {
public static void main(String[] args) {
int score = 75;
boolean passed = score >= 60;
System.out.println("합격? " + passed);
String grade = (score >= 90) ? "A"
: (score >= 80) ? "B"
: (score >= 70) ? "C"
: (score >= 60) ? "D"
: "F";
System.out.println("등급: " + grade);
boolean ok = score > 0 && score <= 100;
System.out.println("유효 범위? " + ok);
}
}
자주 하는 실수
- 객체 비교에 `==` 사용 → `.equals()` 로 교체
- `int a = 1/2;` 가 0 인 줄 모르고 계산
- 후위 `i++` 를 if 조건 안에 섞어 결과가 헷갈림
- `&&` 와 `&` 혼동 (전자는 단락 평가, 후자는 항상 양쪽 평가)
- `Integer` 캐시 때문에 가끔 우연히 `==` 가 통하는 버그
정리
- 정수 vs 실수 연산을 의식적으로 구분합니다
- 객체 비교는 무조건 `.equals()`
- 비트 연산은 플래그·해시 같은 특수 상황에서 유용
- 짧은 회로 평가는 null 체크의 핵심 도구
과제
# 과제 - 03. 연산자와 표현식
## 문제 1 — 윤년 판별
- 파일명: `Homework01.java`
- 핵심 개념: 비교·논리 연산자, 단락 평가
요구사항
- 변수 `year` 에 2024 를 대입합니다.
- 윤년 조건(4의 배수 AND (100의 배수가 아님 OR 400의 배수)) 을 한 표현식으로 작성합니다.
- 결과를 `2024은(는) 윤년? true` 형식으로 출력합니다.
예상 출력
2024은(는) 윤년? true힌트
- `(year % 4 == 0) && (year % 100 != 0 || year % 400 == 0)`
## 문제 2 — 등급 매기기
- 파일명: `Homework02.java`
- 핵심 개념: 삼항 연산자 중첩
요구사항
- 점수 `score = 73` 을 선언합니다.
- 삼항 연산자만 사용해 등급(A/B/C/D/F)을 결정합니다.
- `점수=73 -> 등급=C` 형식으로 출력합니다.
예상 출력
점수=73 -> 등급=C힌트
- `(score >= 90) ? "A" : (score >= 80) ? "B" : ...`
## 문제 3 — 비트로 짝홀 판별
- 파일명: `Homework03.java`
- 핵심 개념: 비트 AND `&`
요구사항
- 1~5 의 정수에 대해 `(n & 1)` 결과로 짝/홀을 출력합니다.
예상 출력
1 -> 홀수
2 -> 짝수
3 -> 홀수
4 -> 짝수
5 -> 홀수힌트
- `for` 반복은 04편에서 자세히 다루지만, 단순 패턴은 미리 사용해도 좋습니다.
## 정답 확인 직접 풀어 본 후 [`answer/`](./answer/) 폴더의 정답과 비교해 보세요.
정답 코드 (homework/answer/)
answer/Homework01.java
/** 윤년 판별. */
public class Homework01 {
public static void main(String[] args) {
int year = 2024;
boolean leap = (year % 4 == 0) && (year % 100 != 0 || year % 400 == 0);
System.out.println(year + "은(는) 윤년? " + leap);
}
}
answer/Homework02.java
/** 삼항 연산자로 학점 결정. */
public class Homework02 {
public static void main(String[] args) {
int score = 73;
String grade = (score >= 90) ? "A"
: (score >= 80) ? "B"
: (score >= 70) ? "C"
: (score >= 60) ? "D"
: "F";
System.out.println("점수=" + score + " -> 등급=" + grade);
}
}
answer/Homework03.java
/** 비트 AND 로 짝/홀 판별. */
public class Homework03 {
public static void main(String[] args) {
for (int n = 1; n <= 5; n++) {
String kind = ((n & 1) == 0) ? "짝수" : "홀수";
System.out.println(n + " -> " + kind);
}
}
}
직접 해 보기
cd 01_기초/03_연산자와_표현식/src
javac Arithmetic.java
java Arithmetic다음 단원
[04_제어문](../04_제어문/) — `if` / `switch` / 반복문을 다룹니다.