1. Introduction: Why String Search Matters in Java
String manipulation은 Java 프로그래밍에서 가장 자주 사용되는 연산 중 하나입니다.
사용자 입력을 검사하거나 파일 내용을 파싱하거나 특정 키워드를 검색할 때, 주어진 문자열에 특정 단어가 포함되어 있는지를 판단해야 할 경우가 많습니다. 이러한 요구를 충족시키기 위해 Java는 contains()라는 편리한 메서드를 제공합니다. 이 메서드를 사용하면 한 문자열이 다른 문자열을 부분적으로 포함하고 있는지를 손쉽게 확인할 수 있습니다. 예를 들어, 오류 메시지에 특정 키워드가 포함되어 있는지를 확인하고 싶다면 contains()를 한 줄의 코드로 구현할 수 있습니다. 특히 웹 애플리케이션, API 처리, 로그 분석 등 대량의 텍스트를 다루는 상황에서는 contains() 메서드가 코드 가독성과 유지보수성을 크게 향상시킵니다.
하지만 대소문자 구분이나 null 가능성 등 중요한 고려사항도 존재합니다. 이 글에서는 Java의 contains() 메서드를 기본 사용법, 흔히 저지르는 실수, 다른 메서드와의 차이점, 실전 활용 사례까지 자세히 설명합니다. 초보자뿐만 아니라 실제 프로젝트에서 Java를 활발히 사용하는 개발자에게도 유용한 정보를 제공하는 것이 목표입니다.
2. Basic Syntax and Characteristics of the contains() Method
Java의 contains() 메서드는 문자열이 부분적으로 다른 문자열을 포함하고 있는지를 판단합니다.
구문은 매우 간단하지만 일상적인 프로그래밍 작업에서 매우 실용적으로 자주 사용됩니다.
Basic Syntax
boolean result = targetString.contains(searchString);
이 메서드는 String 클래스에 속하며, CharSequence(보통 String)를 인자로 받습니다.
반환값은 boolean이며, 대상 문자열이 주어진 부분 문자열을 포함하면 true, 그렇지 않으면 false를 반환합니다.
Sample Code
String message = "Java programming is fun!";
boolean hasKeyword = message.contains("programming");
System.out.println(hasKeyword); // Output: true
위 예시에서 부분 문자열 "programming"이 대상 문자열에 존재하므로 contains()는 true를 반환합니다.
Characteristics of the Method
- 부분 일치만 검사: 정확히 일치하는지를 확인하려면
equals()를 사용하세요. - 대소문자 구분: 예를 들어
"Java"와"java"는 서로 다른 문자열로 취급됩니다(자세한 내용은 아래에서 설명). - 정규식 미지원: 문자열 존재 여부만 단순히 확인하므로 패턴 매칭이 필요할 경우
matches()나Pattern클래스를 사용해야 합니다.
Behavior When null Is Passed
contains()에 null을 전달하면 NullPointerException이 발생합니다. 예를 들어 다음 코드는 예외를 발생시킵니다.
String text = null;
System.out.println(text.contains("test")); // Exception occurs
마찬가지로 대상 문자열 자체가 null인 경우에도 동일한 예외가 발생합니다. 따라서 contains()를 호출하기 전에 null 체크를 수행하는 것이 강력히 권장됩니다.
3. Practical Usage Examples and Important Considerations
Java의 contains() 메서드는 직관적이고 편리하지만, 잘못 사용하면 예상치 못한 버그나 비효율적인 코드가 생길 수 있습니다. 이 섹션에서는 contains()의 기본 사용법과 함께 주의해야 할 핵심 포인트를 설명합니다.
3-1. Basic Usage Example
다음 코드는 대상 문자열에 특정 키워드가 포함되어 있는지를 확인하는 간단한 예시를 보여줍니다.
String sentence = "今日はJavaの勉強をしています。";
if (sentence.contains("Java")) {
System.out.println("Javaが含まれています。");
} else {
System.out.println("Javaは含まれていません。");
}
보시다시피 contains()는 if 문과 함께 사용되어 조건 분기를 수행하는 경우가 많습니다.
3-2. Case Sensitivity
contains() 메서드는 대소문자를 구분합니다. 예를 들어 다음 코드는 false를 반환합니다.
String text = "Welcome to Java";
System.out.println(text.contains("java")); // false
이러한 경우 문자열을 비교하기 전에 소문자(또는 대문자)로 변환하는 것이 일반적입니다:
String text = "Welcome to Java";
System.out.println(text.toLowerCase().contains("java")); // true
이 접근 방식은 입력 케이스의 차이(예: 사용자 입력)를 제거하는 데 도움이 됩니다.
3-3. null 및 빈 문자열 처리
contains()를 사용할 때 가장 중요한 고려 사항 중 하나는 null 처리입니다.
대상 문자열이나 인수가 null인 경우 NullPointerException이 발생합니다.
String text = null;
System.out.println(text.contains("test")); // Runtime error
이 문제를 피하기 위해 항상 null 검사를 추가하세요:
if (text != null && text.contains("test")) {
// Safe to process
}
또한 주의하세요:
빈 문자열("")을 전달하면 항상 true를 반환합니다.
String sample = "test";
System.out.println(sample.contains("")); // true
그러나 이 동작은 실제로 거의 유용하지 않으며, 빈 문자열이 의도치 않게 전달되면 버그를 유발할 수 있습니다.
3-4. 여러 키워드 검색 미지원
contains()는 한 번에 하나의 키워드만 확인할 수 있습니다.
여러 키워드를 확인하려면 contains()를 여러 번 호출하거나 Stream API를 사용해야 합니다.
String target = "エラーコード123:アクセス拒否";
if (target.contains("エラー") || target.contains("拒否")) {
System.out.println("問題のあるメッセージです。");
}
또는 동적 키워드 세트의 경우:
List<String> keywords = Arrays.asList("エラー", "障害", "失敗");
boolean found = keywords.stream().anyMatch(target::contains);
4. contains()와 자주 비교되는 메서드
Java는 문자열 비교나 특정 부분 문자열 존재 확인을 위한 여러 메서드를 제공합니다.
그중 contains()는 “부분 일치”에 사용되지만, 다른 메서드들도 유사한 목적으로 사용됩니다.
이 섹션에서는 이러한 메서드들의 특성과 차이점을 설명하여 적절히 사용하도록 돕습니다.
4-1. equals()와의 차이: 정확 일치 vs. 부분 일치
equals()는 두 문자열이 정확히 동일한지 결정합니다.
반대로, contains()는 부분 일치를 확인합니다.
String a = "Java";
String b = "Java";
System.out.println(a.equals(b)); // true: Exact match
System.out.println(a.contains("av")); // true: Partial match
주요 차이점:
| Comparison | equals() | contains() |
|---|---|---|
| Match Type | Exact match | Partial match |
| Case Sensitivity | Sensitive | Sensitive |
| Argument Type | Object | CharSequence |
사용 지침: 값이 정확히 일치해야 할 때(예: ID 확인) equals()를 사용하세요.
부분 일치가 허용될 때(예: 키워드 검색) contains()를 사용하세요.
4-2. indexOf()와의 차이: 위치가 필요한지 여부
indexOf() 메서드도 문자열 내 부분 문자열 존재를 확인하는 데 사용할 수 있습니다.
차이점은 indexOf()가 발견된 경우 부분 문자열의 시작 인덱스를 반환한다는 것입니다.
부분 문자열을 찾지 못하면 -1을 반환합니다.
String text = "Hello, Java World!";
System.out.println(text.indexOf("Java")); // 7
System.out.println(text.indexOf("Python")); // -1
indexOf()를 사용하여 contains()의 동작을 재현할 수도 있습니다:
if (text.indexOf("Java") >= 0) {
System.out.println("It is contained.");
}
사용 지침: 인덱스가 필요하지 않다면 contains()가 더 읽기 쉽고 선호됩니다.
4-3. matches()와의 차이: 정규 표현식 지원
matches() 메서드는 문자열이 주어진 정규 표현식과 완전히 일치하는지 확인합니다.
반대로, contains()는 리터럴 부분 문자열 일치만 확인하며 regex를 지원하지 않습니다.
String text = "abc123";
System.out.println(text.matches(".*123")); // true
System.out.println(text.contains(".*123")); // false (not regex)
regex 기반 부분 일치를 원한다면 Pattern 클래스를 사용하세요:
4-4. 기능 비교 요약
| Method | Purpose | Return Type | Regex Support | Use Case |
|---|---|---|---|---|
contains() | Partial match | boolean | No | Keyword search |
equals() | Exact match | boolean | No | ID/password checks |
indexOf() | Get match position | int | No | Index-based processing |
matches() | Regex match | boolean | Yes | Find pattern-based strings |
5. 일반적인 사용 사례 및 샘플 코드
Java의 contains() 메서드는 간단하지만 실제 개발 시나리오에서 널리 사용됩니다.
일반적인 사용 사례에는 사용자 입력 검증, 로그 분석, 필터링 작업이 포함됩니다.
이 섹션에서는 해당 코드와 함께 실용적인 예제를 다룹니다.
5-1. 사용자 입력 검증 (금지어 감지)
In forms or chat applications, you may need to detect whether certain prohibited words are included.
String input = "このアプリは最悪だ";
String banned = "最悪";
if (input.contains(banned)) {
System.out.println("不適切な言葉が含まれています。");
}
Handling multiple NG words:
List<String> bannedWords = Arrays.asList("最悪", "バカ", "死ね");
for (String word : bannedWords) {
if (input.contains(word)) {
System.out.println("不適切な言葉が含まれています: " + word);
break;
}
}
5-2. 로그 파일 분석 (특정 메시지 감지)
시스템 또는 애플리케이션 로그를 분석할 때, ERROR나 WARN과 같은 특정 키워드가 포함된 라인만 추출하고 싶을 수 있습니다.
List<String> logs = Arrays.asList(
"[INFO] サーバーが起動しました",
"[ERROR] データベース接続失敗",
"[WARN] メモリ使用率が高い"
);
for (String log : logs) {
if (log.contains("ERROR")) {
System.out.println("エラー発生ログ: " + log);
}
}

5-3. 리스트에서 문자열 필터링 (Stream API 사용)
대용량 데이터셋을 다룰 때, 특정 부분 문자열을 포함하는 요소만 추출하려면 Stream API를 사용하세요:
List<String> users = Arrays.asList("tanaka@example.com", "sato@gmail.com", "yamada@yahoo.co.jp");
List<String> gmailUsers = users.stream()
.filter(email -> email.contains("@gmail.com"))
.collect(Collectors.toList());
System.out.println(gmailUsers); // [sato@gmail.com]
5-4. HTTP 요청 헤더 또는 URL 파싱
웹 개발에서는 라우팅이나 디바이스별 처리를 위해 User-Agent 또는 URL에 포함된 부분 문자열을 확인해야 할 수 있습니다.
String userAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X)";
if (userAgent.contains("iPhone")) {
System.out.println("スマートフォンからのアクセスです。");
}
5-5. 파일 경로 또는 확장자 확인
파일 경로를 사용해 파일 유형을 판단하려면:
String filePath = "/usr/local/data/sample.csv";
if (filePath.contains(".csv")) {
System.out.println("CSVファイルです。");
}
참고: 파일 확장자를 확인할 때는 endsWith(".csv")가 더 정확한 경우가 많습니다.
실용적인 고려 사항
- 정확성이 필요할 때는 정규화(
toLowerCase(),trim()등)를 적용하세요. - 대규모 데이터의 경우 Stream API나 정규식을 고려하세요.
contains()는 부분 일치이므로, 보다 안전한 로직을 위해 다른 조건과 결합하세요.
6. 성능 고려
contains() 메서드는 가독성과 단순성이 뛰어나지만, 대규모 데이터셋을 다루거나 반복 작업을 수행할 때 성능 영향을 고려해야 합니다.
이 섹션에서는 contains()의 처리 비용과 효율성을 높이기 위한 대안 접근법을 설명합니다.
6-1. contains()의 내부 동작 및 시간 복잡도
contains() 메서드는 대상 문자열을 시작부터 순차적으로 검색하여 부분 문자열을 찾습니다.
내부적으로 indexOf() 메서드에 의존하며, 최악의 경우 시간 복잡도는 다음과 같습니다:
O(n * m)
– n = 대상 문자열의 길이
– m = 검색 문자열의 길이
무거운 처리 예시:
for (String line : hugeTextList) {
if (line.contains("error")) {
// processing
}
}
대규모 루프 내에서 반복될 경우 성능 미칠 수 있습니다.
6-2. 빈번한 검색 시 성능 향상 기법
대규모 데이터셋에서 contains()를 반복적으로 사용할 때, 다음 기법들이 처리 속도를 향상시킬 수 있습니다:
• 모든 문자열을 미리 소문자로 변환하기
각 비교 시마다 toLowerCase()를 호출하는 대신, 사전에 문자열을 정규화하세요:
List<String> normalizedList = originalList.stream()
.map(String::toLowerCase)
.collect(Collectors.toList());
• parallel()을 사용한 Stream API로 병렬 처리하기
CPU 코어를 활용해 검색을 가속화합니다:
List<String> result = hugeTextList.parallelStream()
.filter(line -> line.contains("keyword"))
.collect(Collectors.toList());
• 복잡한 검색 패턴에 정규식 사용하기
조건이 복잡하고 하나의 정규식으로 표현할 수 있다면 Pattern이 더 나은 성능을 보일 수 있습니다:
Pattern pattern = Pattern.compile("error|fail|fatal");
for (String log : logs) {
if (pattern.matcher(log).find()) {
// matched
}
}
6-3. 메모리 효율성과 재사용성 고려 사항
toLowerCase() 나 substring()과 같이 문자열을 자주 변환하는 작업은 불필요한 문자열 객체를 많이 생성하여 메모리 사용량에 영향을 줄 수 있습니다. 이는 장시간 실행되는 애플리케이션이나 서버‑사이드 처리에서 특히 중요합니다.
핵심 포인트:
- 불필요한 문자열 인스턴스 생성을 피합니다.
- 대용량 데이터셋의 경우 버퍼링이나 청크 처리 방식을 고려합니다.
contains()결과를 캐시하면 특정 상황에서 성능이 향상될 수 있습니다.
7. 다른 프로그래밍 언어와의 비교
Java의 contains() 메서드는 간단하고 신뢰성 있는 부분 문자열 매칭을 제공하지만, 다른 언어들도 각각의 특성을 가진 유사 기능을 제공합니다. 이 섹션에서는 Python, JavaScript, C#에서의 부분 문자열 검사 방식을 비교하여 차이점과 유사점을 살펴봅니다.
7-1. Python: in 연산자를 이용한 간단한 부분 매치
Python에서는 in 연산자를 사용해 부분 문자열 포함 여부를 확인할 수 있습니다:
text = "Hello, Python!"
if "Python" in text:
print("含まれています")
이 구문은 매우 가독성이 높아 거의 자연어와 같으며 학습 비용이 최소화됩니다.
차이점 및 참고 사항:
in은 메서드가 아니라 언어 연산자입니다.- Python도 문자열 비교 시 대소문자를 구분합니다.
None을 사용하면 예외가 발생하므로 null 체크가 필요합니다.
7-2. JavaScript: includes() 로 부분 매치
JavaScript(ES6+)에서는 includes() 메서드를 사용할 수 있습니다:
const text = "JavaScript is fun";
console.log(text.includes("fun")); // true
이 메서드는 Java의 contains()와 매우 유사하며 사고 방식 전환이 쉽습니다.
차이점 및 참고 사항:
undefined를 전달해도 예외가 발생하지 않고 단순히false를 반환합니다.includes()는 배열에도 적용 가능해 활용도가 높습니다.
7-3. C#: Java와 유사한 Contains()
C# 역시 Java와 비슷한 동작을 하는 Contains() 메서드를 제공합니다:
string text = "Welcome to C#";
bool result = text.Contains("C#");
차이점 및 참고 사항:
- C#의
Contains()는 기본적으로 대소문자를 구분하지만,StringComparison.OrdinalIgnoreCase를 사용해 대소문자를 무시할 수 있습니다. null을 전달하면ArgumentNullException이 발생합니다.
7-4. 언어별 비교 표
| Language | Example Syntax | Case Sensitivity | Notes |
|---|---|---|---|
| Java | "abc".contains("a") | Sensitive | Throws exception on null |
| Python | "a" in "abc" | Sensitive | Most intuitive syntax |
| JavaScript | "abc".includes("a") | Sensitive | Also works for arrays |
| C# | "abc".Contains("a") | Sensitive (configurable) | Comparison mode can be chosen |
요약: 상황에 맞는 구문 선택
부분 문자열 검사는 대부분의 언어에서 공통적인 요구사항이지만, 각 언어마다 제공하는 메서드나 구문이 다릅니다.
Java의 contains()는 안정성과 가독성이 뛰어나 기업용 시스템 및 유지보수가 중요한 애플리케이션에 적합합니다.
Python과 JavaScript는 더 간결하고 직관적인 구문을 제공해 가벼운 스크립트나 빠른 프로토타이핑에 유리합니다.
공통 개념과 각 언어의 특성을 이해하면 다양한 환경에서 보다 안전하고 효율적인 코드를 작성할 수 있습니다.
8. 자주 묻는 질문 (FAQ)
아래는 Java의 contains() 메서드와 관련해 자주 제기되는 질문과 그에 대한 답변입니다. 어려운 점을 파악하고 흔히 발생하는 함정을 피하는 데 도움이 됩니다.
Q1. contains()는 대소문자를 구분하나요?
예, 대소문자를 구분합니다.
예를 들어, "Java".contains("java")는 false를 반환합니다.
해결 방법:
String input = "Welcome to Java";
boolean result = input.toLowerCase().contains("java");
Q2. 정규식을 이용해 부분 매치를 확인하려면 어떻게 해야 하나요?
contains() 는 정규식을 지원하지 않습니다.
대신 matches() 나 Pattern 클래스를 사용하십시오.
예시 (숫자 패턴 확인):
import java.util.regex.Pattern;
import java.util.regex.Matcher;
String text = "注文番号: A123456";
Pattern pattern = Pattern.compile("A\d+");
Matcher matcher = pattern.matcher(text);
if (matcher.find()) {
System.out.println("パターンに一致しました。");
}
Q3. contains()를 null에 호출하면 어떻게 되나요?
NullPointerException이 발생합니다.
String target = null;
System.out.println(target.contains("test")); // Error
솔루션:
if (target != null && target.contains("test")) {
System.out.println("含まれています。");
}
Q4. contains()에 빈 문자열 (“”)을 전달하면 어떻게 되나요?
항상 true를 반환합니다.
String text = "Java";
System.out.println(text.contains("")); // true
공식 사양의 일부이지만, 이 동작은 거의 유용하지 않으며 빈 문자열이 의도되지 않은 경우 예상치 못한 버그를 일으킬 수 있습니다.
Q5. contains()로 여러 키워드를 한 번에 검색할 수 있나요?
아니요. 각 호출은 하나의 키워드만 확인합니다.
String text = "本日はシステムエラーが発生しました";
if (text.contains("エラー") || text.contains("障害") || text.contains("失敗")) {
System.out.println("問題が検出されました。");
}
동적 접근법:
List<String> keywords = Arrays.asList("エラー", "障害", "失敗");
boolean found = keywords.stream().anyMatch(text::contains);
Q6. contains()와 indexOf()를 언제 사용해야 하나요?
contains()는 불리언을 반환하며, indexOf()는 숫자 인덱스를 반환합니다.
- 부분 문자열이 존재하는지 단순히 알고 싶을 때
contains()를 사용하세요. - 위치도 필요할 때
indexOf()를 사용하세요.String text = "Error: Disk full"; if (text.contains("Error")) { int pos = text.indexOf("Error"); System.out.println("Position: " + pos); }
9. 결론
Java의 contains() 메서드는 특정 부분 문자열이 문자열 내에 포함되어 있는지 확인하는 강력하고 편리한 도구입니다.
이 메서드는 사용자 입력 검증, 로그 분석, 데이터 필터링 등 다양한 시나리오에서 널리 사용됩니다.
이 기사에서 우리는 다음을 다루었습니다:
- 기본 구문과 반환 값
- 대소문자 민감성과 이를 처리하는 방법
- null 및 빈 문자열 처리
- 다른 문자열 비교 메서드와의 차이점
- 실제 사용 사례: 검증, 로그 검색, Stream 처리
- 성능 고려사항 및 최적화 기법
- Python, JavaScript, C#과의 비교
- 자주 묻는 질문 및 문제 해결 팁
contains()는 직관적이고 다재다능하지만, 대규모 데이터셋, 빈번한 호출, 또는 복잡한 검색 조건이 포함된 경우 사용을 신중히 평가해야 합니다.
정규화, 병렬 처리, 정규 표현식, 캐싱 전략을 결합함으로써 성능과 가독성을 모두 유지할 수 있습니다. contains()는 Java에서 문자열 작업의 기본이므로, 이 기사가 개발 프로젝트에서 더 안전하고 효과적으로 사용하도록 돕기를 바랍니다.

