1. 소개
왜 문자열 비교가 Java에서 중요한가?
Java 프로그래밍에서는 문자열이 다양한 상황에서 사용됩니다. 사용자 이름 확인, 폼 입력 검증, API 응답 확인 모두 문자열 비교가 필요합니다.
이 시점에서 “문자열을 올바르게 비교하는 방법”은 초보자에게 흔히 겪는 난관입니다. 특히 == 연산자와 equals() 메서드의 차이를 이해하지 못하면 예상치 못한 버그가 발생할 수 있습니다.
“==”와 “equals” 차이를 이해하지 못했을 때의 위험
다음 코드를 고려해 보세요:
String a = "apple";
String b = new String("apple");
System.out.println(a == b); // result: false
System.out.println(a.equals(b)); // result: true
많은 사람들이 이 출력에 놀라곤 합니다. 문자열이 동일함에도 ==는 false를 반환하고 equals()는 true를 반환합니다. 이는 Java가 문자열을 레퍼런스 타입으로 취급하고 ==가 레퍼런스 주소를 비교하기 때문입니다.
문자열을 올바르게 비교하는 방법을 이해하면 프로그램의 신뢰성과 가독성에 직접적인 영향을 미칩니다. 제대로 이해하면 버그가 발생하기 전에 예방할 수 있습니다.
이 글에서 배울 내용
이 글은 Java 문자열 비교를 기본부터 실용적인 적용까지 설명합니다. 다음과 같은 질문에 답합니다:
==와equals()의 차이는 무엇인가?- 대소문자를 무시하고 문자열을 비교하려면 어떻게 해야 하나요?
- 문자열을 사전식으로 비교하려면 어떻게 해야 하나요?
- null과 비교할 때 예외를 피하려면 어떻게 해야 하나요?
실제 예제를 통해 올바른 문자열 비교 실천법에 대한 확고한 이해를 얻을 수 있습니다.
2. Java 문자열 기본
문자열은 레퍼런스 타입이다
Java에서 String 타입은 int나 boolean 같은 원시 타입이 아니라 레퍼런스 타입입니다. String 변수는 실제 문자 자체를 저장하지 않고 힙 메모리에 저장된 객체에 대한 레퍼런스를 저장합니다.
예를 들어:
String a = "hello";
String b = "hello";
Java의 문자열 인터닝 메커니즘 때문에 a와 b가 동일한 "hello" 리터럴을 가리킬 수 있습니다.
문자열 리터럴과 new String()의 차이
Java는 반복되는 문자열 리터럴을 동일한 레퍼런스를 재사용함으로써 최적화합니다:
String s1 = "apple";
String s2 = "apple";
System.out.println(s1 == s2); // true (same literal, interned)
하지만 new를 사용하면 항상 새로운 객체가 생성됩니다:
String s3 = new String("apple");
System.out.println(s1 == s3); // false (different references)
System.out.println(s1.equals(s3)); // true (same content)
따라서 ==는 레퍼런스를, equals()는 내용을 확인합니다.
문자열은 불변이다
또 다른 핵심 특징은 String이 불변(immutable)이라는 점입니다. 한 번 생성된 문자열은 변경할 수 없습니다.
String original = "hello";
original = original + " world";
이 코드는 원본을 수정하는 것이 아니라 새로운 String 객체를 생성합니다.
3. 문자열 비교 메서드
== 로 레퍼런스 비교
==는 객체 레퍼런스를 비교합니다:
String a = "Java";
String b = new String("Java");
System.out.println(a == b); // false
내용 비교에는 사용해서는 안 됩니다.
equals() 로 내용 비교
equals()는 문자열 내용을 비교하는 올바른 방법입니다:
String a = "Java";
String b = new String("Java");
System.out.println(a.equals(b)); // true
NullPointerException 방지
String input = null;
System.out.println(input.equals("test")); // Exception!
상수-우선 스타일을 사용합니다:
System.out.println("test".equals(input)); // false, safe
equalsIgnoreCase() 로 대소문자 무시
String a = "Hello";
String b = "hello";
System.out.println(a.equalsIgnoreCase(b)); // true
compareTo() 로 사전식 비교
- 0 → 동일
- 음수 → 호출자가 앞에 있음
- 양수 → 호출자가 뒤에 있음
String a = "apple"; String b = "banana"; System.out.println(a.compareTo(b)); // negative
4. 실용 예제
사용자 로그인 확인
String inputUsername = "Naohiro";
String registeredUsername = "naohiro";
if (registeredUsername.equalsIgnoreCase(inputUsername)) {
System.out.println("Login successful");
} else {
System.out.println("Username does not match");
}
Passwords should always use equals() because case sensitivity is required. 
폼 입력 검증
String selectedOption = request.getParameter("plan");
if ("premium".equals(selectedOption)) {
System.out.println("Premium plan selected.");
} else {
System.out.println("Other plan selected.");
}
여러 문자열 검사를 이용한 분기 로직
String cmd = args[0];
if ("start".equals(cmd)) {
startApp();
} else if ("stop".equals(cmd)) {
stopApp();
} else {
System.out.println("Invalid command");
}
switch (cmd) {
case "start":
startApp();
break;
case "stop":
stopApp();
break;
default:
System.out.println("Unknown command");
}
null 안전하게 처리하기
String keyword = null;
if ("search".equals(keyword)) {
System.out.println("Searching...");
}
5. 성능 및 최적화
문자열 비교 비용
equals()와 compareTo()는 내부적으로 문자를 비교합니다. 긴 문자열이나 반복적인 비교에서는 성능에 영향을 줄 수 있습니다.
성능을 위한 String.intern() 사용
String a = new String("hello").intern();
String b = "hello";
System.out.println(a == b); // true
메모리 압박을 피하기 위해 필요할 때만 사용하십시오.
equalsIgnoreCase()의 성능 영향
String input = userInput.toLowerCase();
if ("admin".equals(input)) {
// fast comparison
}
StringBuilder / StringBuffer 사용
StringBuilder sb = new StringBuilder();
sb.append("user_");
sb.append("123");
String result = sb.toString();
if (result.equals("user_123")) {
// comparison
}
캐시 또는 맵을 사용해 비교 횟수 줄이기
Map<String, Runnable> commandMap = new HashMap<>();
commandMap.put("start", () -> startApp());
commandMap.put("stop", () -> stopApp());
Runnable action = commandMap.get(inputCommand);
if (action != null) {
action.run();
}
6. 자주 묻는 질문
Q1. ==와 equals()의 차이점은 무엇인가요?
A.
==는 레퍼런스를 비교합니다equals()는 문자열 내용을 비교합니다
Q2. 변수값이 null일 때 equals()가 오류를 발생시키는 이유는 무엇인가요?
String input = null;
input.equals("test"); // Exception
상수-우선 비교를 사용하세요:
"test".equals(input);
Q3. 대소문자를 무시하고 문자열을 비교하려면 어떻게 해야 하나요?
stringA.equalsIgnoreCase(stringB);
Q4. 알파벳 순서를 비교하려면 어떻게 해야 하나요?
a.compareTo(b);
7. 결론
올바른 비교 방법을 선택하는 것이 중요합니다
String은 레퍼런스 타입이기 때문에 잘못된 비교는 종종 예상치 못한 동작을 초래합니다. ==와 equals()의 차이를 이해하는 것이 필수적입니다.
체크리스트
==: 레퍼런스를 비교합니다equals(): 내용을 비교합니다equalsIgnoreCase(): 대소문자를 무시합니다compareTo(): 사전 순서를 비교합니다"constant".equals(variable): null 안전합니다- 무거운 비교에서는
intern()이나 캐시를 사용하세요
실용적이고 필수적인 지식
문자열 비교는 로그인 검사, 입력 검증, 데이터베이스 작업, 분기 로직 및 다양한 일상 작업에 등장합니다. 올바른 기법을 알면 더 안전하고 신뢰성 높은 코드를 작성할 수 있습니다. Java에서 문자열을 다룰 때 이 가이드를 참고하세요.

