본문으로 건너뛰기

Ch 3.4 비교 연산자 (Comparison Operator)

비교 연산자는 두 피연산자를 비교하여 true 또는 false 를 반환합니다. 조건문(if, while, for)과 함께 사용되어 프로그램의 흐름을 제어하는 핵심 요소입니다.


1. 비교 연산자 6가지 완전 정리

연산자이름설명예시결과
==동등두 값이 같으면 true5 == 5true
!=불동등두 값이 다르면 true5 != 3true
>초과좌변이 우변보다 크면 true5 > 3true
<미만좌변이 우변보다 작으면 true3 < 5true
>=이상좌변이 우변보다 크거나 같으면 true5 >= 5true
<=이하좌변이 우변보다 작거나 같으면 true3 <= 5true
public class ComparisonBasic {
public static void main(String[] args) {
int a = 10, b = 5, c = 10;

System.out.println("a == b : " + (a == b)); // false
System.out.println("a == c : " + (a == c)); // true
System.out.println("a != b : " + (a != b)); // true
System.out.println("a > b : " + (a > b)); // true
System.out.println("a < b : " + (a < b)); // false
System.out.println("a >= c : " + (a >= c)); // true
System.out.println("b <= c : " + (b <= c)); // true
}
}
boolean 타입은 대소 비교 불가

boolean 타입은 ==!=만 사용 가능하며, >, <, >=, <=는 사용할 수 없습니다.

boolean flag = true;
// System.out.println(flag > false); // 컴파일 에러!
System.out.println(flag == true); // true (가능하지만 flag 자체를 쓰는 것이 더 관용적)

2. 기본형 비교: 값 자체를 비교

int, long, double, boolean, char기본형(Primitive)== 연산자를 사용하면 값(Value) 자체를 직접 비교 합니다.

public class PrimitiveComparison {
public static void main(String[] args) {
int x = 100;
int y = 100;
System.out.println(x == y); // true (값이 같음)

double d1 = 3.14;
double d2 = 3.14;
System.out.println(d1 == d2); // true

char c1 = 'A';
char c2 = 65; // 'A'의 유니코드 값
System.out.println(c1 == c2); // true (char는 내부적으로 숫자)

boolean b1 = true;
boolean b2 = true;
System.out.println(b1 == b2); // true
}
}

3. 참조형 비교: ==는 주소값 비교

객체(참조형)에 ==를 사용하면 객체의 내용이 아닌 메모리 주소값(참조값)을 비교 합니다. 따라서 내용이 같더라도 다른 객체라면 false를 반환합니다.

public class ReferenceComparison {
public static void main(String[] args) {
// new 키워드로 생성한 두 배열: 내용은 같지만 서로 다른 객체
int[] arr1 = {1, 2, 3};
int[] arr2 = {1, 2, 3};
int[] arr3 = arr1; // arr1의 참조값을 복사

System.out.println(arr1 == arr2); // false (다른 객체, 다른 주소)
System.out.println(arr1 == arr3); // true (같은 객체를 가리킴)

// 배열 내용 비교는 Arrays.equals() 사용
System.out.println(java.util.Arrays.equals(arr1, arr2)); // true (내용 비교)
}
}

4. String 비교 함정: String Pool

String 타입은 자바의 특별한 메모리 관리(String Pool) 때문에 == 비교 시 예상치 못한 결과가 나올 수 있습니다.

public class StringComparison {
public static void main(String[] args) {
// 리터럴 방식: String Pool에서 재사용
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); // true (같은 Pool 객체를 참조)
System.out.println(s1.equals(s2)); // true

// new 키워드: 항상 새로운 객체 생성 (Pool 밖)
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(s3 == s4); // false (서로 다른 객체)
System.out.println(s3.equals(s4)); // true (내용은 같음)

// 리터럴과 new 비교
System.out.println(s1 == s3); // false (Pool 객체 vs 힙 객체)
System.out.println(s1.equals(s3)); // true

// intern(): Pool로 등록하여 == 비교 가능하게 함 (잘 사용 안 함)
String s5 = s3.intern();
System.out.println(s1 == s5); // true (intern 후 Pool 참조)
}
}
문자열 비교는 항상 .equals() 사용

String 비교 시 == 는 사용하지 마세요. 리터럴 방식에서는 우연히 true가 나올 수 있지만, new String()이나 메서드에서 반환된 문자열은 항상 false가 됩니다.

항상 .equals() 를 사용하세요!

// 나쁜 예
if (userInput == "yes") { ... }

// 좋은 예
if ("yes".equals(userInput)) { ... } // null 안전 (좌변에 상수)
if (userInput.equals("yes")) { ... } // userInput이 null이면 NullPointerException

5. equals() 메서드 심화

모든 자바 클래스는 Object 클래스를 상속하므로 equals() 메서드를 가집니다. 기본 구현은 == 와 동일(주소 비교)하지만, String, Integer, List 등 많은 클래스가 내용 비교 로 오버라이드합니다.

public class EqualsMethod {
public static void main(String[] args) {
// String.equals(): 내용 비교 (오버라이드됨)
String s1 = new String("Java");
String s2 = new String("Java");
System.out.println(s1.equals(s2)); // true

// Integer.equals(): 값 비교 (오버라이드됨)
Integer i1 = new Integer(100);
Integer i2 = new Integer(100);
System.out.println(i1.equals(i2)); // true

// Integer 캐싱 주의: -128 ~ 127 범위는 캐싱됨
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true (캐싱된 객체)

Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false (캐싱 범위 초과)
System.out.println(c.equals(d)); // true

// 대소문자 무시 비교
String str = "Hello";
System.out.println(str.equals("hello")); // false
System.out.println(str.equalsIgnoreCase("hello")); // true
}
}

6. Objects.equals(): null 안전 비교

String.equals() 는 좌변 객체가 null이면 NullPointerException이 발생합니다. java.util.Objects.equals() 를 사용하면 null을 안전하게 처리할 수 있습니다.

import java.util.Objects;

public class NullSafeComparison {
public static void main(String[] args) {
String name = null;

// 위험한 방법: NullPointerException 발생
// System.out.println(name.equals("Alice")); // NPE!

// 안전한 방법 1: null 체크 먼저
System.out.println(name != null && name.equals("Alice")); // false

// 안전한 방법 2: 상수를 왼쪽에 (null은 equals를 가지지 않으므로)
System.out.println("Alice".equals(name)); // false (NPE 없음)

// 안전한 방법 3: Objects.equals() (null 처리 내장)
System.out.println(Objects.equals(name, "Alice")); // false
System.out.println(Objects.equals(null, null)); // true
System.out.println(Objects.equals("Alice", null)); // false

// Objects.equals 내부 동작:
// (a == b) || (a != null && a.equals(b))
}
}

7. compareTo() 메서드

==, != 만으로는 "얼마나 큰지/작은지"를 알 수 없습니다. Comparable 인터페이스의 compareTo() 메서드는 두 객체의 순서 를 비교하여 정수를 반환합니다.

반환값의미
음수(< 0)호출 객체가 인수보다 작다
0두 객체가 같다
양수(> 0)호출 객체가 인수보다 크다
public class CompareToExample {
public static void main(String[] args) {
// String.compareTo(): 사전(알파벳) 순서 비교
String apple = "apple";
String banana = "banana";
String apple2 = "apple";

System.out.println(apple.compareTo(banana)); // 음수 (a < b 알파벳 순)
System.out.println(banana.compareTo(apple)); // 양수
System.out.println(apple.compareTo(apple2)); // 0 (같음)

// Integer.compareTo(): 숫자 크기 비교
Integer n1 = 10;
Integer n2 = 20;
System.out.println(n1.compareTo(n2)); // -1 (10 < 20)
System.out.println(n2.compareTo(n1)); // 1 (20 > 10)
System.out.println(n1.compareTo(10)); // 0 (같음)

// 정렬에 활용 (compareTo의 주된 용도)
String[] fruits = {"banana", "cherry", "apple"};
java.util.Arrays.sort(fruits); // compareTo 기반 정렬
System.out.println(java.util.Arrays.toString(fruits)); // [apple, banana, cherry]
}
}

8. NaN 비교 주의사항

float/double 의 특수값 NaN(Not a Number)은 자기 자신과도 같지 않습니다. 모든 비교 연산에서 false를 반환하는 유일한 값입니다.

public class NaNComparison {
public static void main(String[] args) {
double nan = Double.NaN;

System.out.println(nan == nan); // false (NaN은 자기 자신과도 !=)
System.out.println(nan != nan); // true
System.out.println(nan > 0); // false
System.out.println(nan < 0); // false
System.out.println(nan == 0); // false

// NaN 체크는 반드시 isNaN() 사용
System.out.println(Double.isNaN(nan)); // true
System.out.println(Float.isNaN(Float.NaN)); // true

// NaN이 발생하는 경우
double result1 = 0.0 / 0.0;
double result2 = Math.sqrt(-1);
System.out.println(Double.isNaN(result1)); // true
System.out.println(Double.isNaN(result2)); // true
}
}
NaN 비교는 isNaN()으로만

nan == nanfalse 라는 점은 자바(IEEE 754 표준)의 의도적인 설계입니다. 항상 Double.isNaN() 또는 Float.isNaN()을 사용하세요.


9. 실전 예제: 성적 등급 판별 프로그램

import java.util.Scanner;

public class GradeChecker {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);

System.out.print("학생 이름을 입력하세요: ");
String name = scanner.nextLine();

System.out.print("점수를 입력하세요 (0~100): ");
int score = scanner.nextInt();

// 유효성 검사: 점수 범위 확인
if (score < 0 || score > 100) {
System.out.println("오류: 점수는 0~100 사이여야 합니다.");
return;
}

// 등급 판별
String grade;
String comment;

if (score >= 90) {
grade = "A";
comment = "우수";
} else if (score >= 80) {
grade = "B";
comment = "양호";
} else if (score >= 70) {
grade = "C";
comment = "보통";
} else if (score >= 60) {
grade = "D";
comment = "미흡";
} else {
grade = "F";
comment = "불합격";
}

// 합격 여부 (60점 이상)
boolean passed = score >= 60;

// 우등상 여부 (95점 이상)
boolean honor = score >= 95;

// 출력
System.out.println();
System.out.println("====== 성적 결과 ======");
System.out.println("이름 : " + name);
System.out.println("점수 : " + score + "점");
System.out.println("등급 : " + grade + " (" + comment + ")");
System.out.println("합격 : " + (passed ? "합격" : "불합격"));
if (honor) {
System.out.println("축하합니다! 우등상 수여 대상입니다.");
}

// 다른 점수와 비교 (compareTo 활용)
int passingScore = 60;
int diff = score - passingScore;
if (passed) {
System.out.println("합격 기준보다 " + diff + "점 높습니다.");
} else {
System.out.println("합격까지 " + Math.abs(diff) + "점 부족합니다.");
}

scanner.close();
}
}

예시 실행 결과 (점수 87 입력 시):

학생 이름을 입력하세요: 김철수
점수를 입력하세요 (0~100): 87

====== 성적 결과 ======
이름 : 김철수
점수 : 87점
등급 : B (양호)
합격 : 합격
합격 기준보다 27점 높습니다.

10. 핵심 정리

비교 대상방법주의사항
기본형(int, double 등)==, !=, >, < 직접 사용없음
String.equals(), .equalsIgnoreCase()== 사용 금지
null 포함 가능 객체Objects.equals(a, b)NPE 방지
순서 비교.compareTo()음수/0/양수 반환
NaNDouble.isNaN(), Float.isNaN()==로 비교 불가