Mistrovství s contains() v Javě: Jak provádět efektivní vyhledávání podřetězců

目次

1. Úvod: Proč je vyhledávání v řetězcích důležité v Javě

Manipulace s řetězci je jednou z nejběžněji používaných operací při programování v Javě.
Ať už kontrolujete uživatelský vstup, parsujete obsah souborů nebo vyhledáváte specifická klíčová slova, často potřebujete určit, zda je v daném řetězci obsaženo určité slovo.

K uspokojení těchto potřeb poskytuje Java pohodlnou metodu nazvanou contains().
S touto metodou můžete snadno určit, zda jeden řetězec částečně obsahuje jiný.
Například pokud chcete zkontrolovat, zda chybová zpráva obsahuje specifické klíčové slovo, contains() vám to umožní udělat v jediném řádku kódu.

Zejména ve scénářích zahrnujících velké objemy textu – jako jsou webové aplikace, zpracování API nebo analýza logů – metoda contains() výrazně zlepšuje čitelnost a udržitelnost kódu.
Nicméně existují také důležité úvahy, jako je citlivost na velikost písmen a možnost null.

Tento článek vysvětluje metodu contains() v Javě podrobně – od základního použití a běžných chyb až po rozdíly oproti jiným metodám a praktické aplikace.
Naším cílem je poskytnout užitečné informace nejen pro začátečníky, ale i pro vývojáře, kteří aktivně používají Javu v reálných projektech.

2. Základní syntaxe a charakteristiky metody contains()

Metoda contains() v Javě určuje, zda řetězec částečně obsahuje jiný řetězec.
Její syntaxe je velmi jednoduchá, přesto je vysoce praktická a často se používá v běžných programovacích úkolech.

Základní syntaxe

boolean result = targetString.contains(searchString);

Metoda patří do třídy String a přijímá jako argument CharSequence (běžně String).
Její návratová hodnota je boolean: true, pokud cílový řetězec obsahuje daný podřetězec, a false jinak.

Ukázkový kód

String message = "Java programming is fun!";
boolean hasKeyword = message.contains("programming");

System.out.println(hasKeyword); // Output: true

V příkladu výše je podřetězec "programming" přítomen v cílovém řetězci, takže contains() vrátí true.

Charakteristiky metody

  • Kontroluje pouze částečnou shodu: Pokud potřebujete přesnou shodu, použijte místo toho equals().
  • Citlivé na velikost písmen: Například "Java" a "java" jsou považovány za různé (podrobnosti vysvětleny níže).
  • Nepodporuje regulární výrazy: Protože jednoduše kontroluje přítomnost řetězce, pro shodu vzorů použijte matches() nebo třídu Pattern.

Chování při předání null

Předání null do contains() spustí NullPointerException.
Například následující kód vyvolá výjimku:

String text = null;
System.out.println(text.contains("test")); // Exception occurs

Stejně tak, pokud je samotný cílový řetězec null, bude vyvolána stejná výjimka.
Proto je vysoce doporučeno provádět kontroly null před voláním contains().

3. Praktické příklady použití a důležité úvahy

Metoda contains() v Javě je velmi intuitivní a pohodlná, ale nesprávné použití může vést k neočekávaným chybám nebo neefektivnímu kódu.
Tato sekce vysvětluje základní použití contains() spolu s klíčovými body, na které byste měli být opatrní.

3-1. Příklad základního použití

Následující kód demonstruje jednoduchý příklad kontroly, zda cílový řetězec obsahuje specifické klíčové slovo:

String sentence = "今日はJavaの勉強をしています。";

if (sentence.contains("Java")) {
    System.out.println("Javaが含まれています。");
} else {
    System.out.println("Javaは含まれていません。");
}

Jak je znázorněno, contains() se často kombinuje s příkazy if pro podmíněné větvení.

3-2. Citlivost na velikost písmen

Metoda contains() je citlivá na velikost písmen.
Například následující kód vrátí false:

String text = "Welcome to Java";
System.out.println(text.contains("java")); // false

V takových případech je běžné převést řetězce na malá (nebo velká) písmena před porovnáním:

String text = "Welcome to Java";
System.out.println(text.toLowerCase().contains("java")); // true

Tento přístup pomáhá eliminovat rozdíly v velikosti písmen vstupu (např. vstup uživatele).

3-3. Zpracování null a prázdných řetězců

Jedním z nejdůležitějších aspektů při používání contains() je zacházení s null. Pokud je cílový řetězec nebo argument null, dojde k NullPointerException.

String text = null;
System.out.println(text.contains("test")); // Runtime error

Aby se tomuto problému předešlo, vždy přidejte kontrolu na null:

if (text != null && text.contains("test")) {
    // Safe to process
}

Také poznámka: Předání prázdného řetězce ("") vždy vrátí true.

String sample = "test";
System.out.println(sample.contains("")); // true

Toto chování je však v praxi zřídka užitečné a může neúmyslně vést k chybám, pokud jsou prázdné řetězce předány neúmyslně.

3-4. Nepodporuje vyhledávání více klíčových slov

contains() může kontrolovat pouze jedno klíčové slovo najednou. Pro kontrolu více klíčových slov musíte buď volat contains() vícekrát, nebo použít Stream API.

String target = "エラーコード123:アクセス拒否";
if (target.contains("エラー") || target.contains("拒否")) {
    System.out.println("問題のあるメッセージです。");
}

Nebo pro dynamické sady klíčových slov:

List<String> keywords = Arrays.asList("エラー", "障害", "失敗");
boolean found = keywords.stream().anyMatch(target::contains);

4. Metody často srovnávané s contains()

Java poskytuje několik metod pro porovnávání řetězců nebo kontrolu, zda konkrétní podřetězec existuje. Mezi nimi se contains() používá pro „částečnou shodu“, ale i jiné metody slouží k podobným účelům. Tato sekce vysvětluje vlastnosti a rozdíly těchto metod, aby vám pomohla je používat správně.

4-1. Rozdíl od equals(): Přesná shoda vs. částečná shoda

equals() určuje, zda jsou dva řetězce naprosto identické. Naopak contains() kontroluje částečné shody.

String a = "Java";
String b = "Java";

System.out.println(a.equals(b));      // true: Exact match
System.out.println(a.contains("av")); // true: Partial match

Hlavní rozdíly:

Comparisonequals()contains()
Match TypeExact matchPartial match
Case SensitivitySensitiveSensitive
Argument TypeObjectCharSequence

Pokyny pro použití:
Použijte equals(), když se hodnoty musí shodovat přesně (např. ověření ID).
Použijte contains(), když jsou částečné shody přijatelné (např. vyhledávání klíčových slov).

4-2. Rozdíl od indexOf(): Potřebujete-li pozici

Metoda indexOf() může být také použita k ověření, zda podřetězec existuje v řetězci. Rozdíl spočívá v tom, že indexOf() vrací počáteční index podřetězce, pokud je nalezen. Pokud podřetězec není nalezen, vrátí -1.

String text = "Hello, Java World!";
System.out.println(text.indexOf("Java"));    // 7
System.out.println(text.indexOf("Python"));  // -1

Můžete také použít indexOf() k napodobení chování contains():

if (text.indexOf("Java") >= 0) {
    System.out.println("It is contained.");
}

Pokyny pro použití:
Pokud nepotřebujete index, contains() je čitelnější a vhodnější.

4-3. Rozdíl od matches(): Podpora regulárních výrazů

Metoda matches() kontroluje, zda řetězec úplně odpovídá zadanému regulárnímu výrazu. Naopak contains() kontroluje pouze doslovné podřetězce a nepodporuje regex.

String text = "abc123";
System.out.println(text.matches(".*123")); // true
System.out.println(text.contains(".*123")); // false (not regex)

Pokud chcete částečné vyhledávání založené na regexu, použijte třídu Pattern:

4-4. Shrnutí srovnání funkcí

MethodPurposeReturn TypeRegex SupportUse Case
contains()Partial matchbooleanNoKeyword search
equals()Exact matchbooleanNoID/password checks
indexOf()Get match positionintNoIndex-based processing
matches()Regex matchbooleanYesFind pattern-based strings

5. Běžné případy použití a ukázkový kód

Java’s contains() method is simple yet widely used in real development scenarios.
Typické použití zahrnují validaci uživatelského vstupu, analýzu logů a filtrační operace.
Tato sekce pokrývá praktické příklady s odpovídajícím kódem.

5-1. Validace uživatelského vstupu (Detekce zakázaných slov)

V formulářích nebo chatových aplikacích můžete potřebovat detekovat, zda jsou zahrnuty určitá zakázaná slova.

String input = "このアプリは最悪だ";
String banned = "最悪";

if (input.contains(banned)) {
    System.out.println("不適切な言葉が含まれています。");
}

Zpracování více NG slov:

List<String> bannedWords = Arrays.asList("最悪", "バカ", "死ね");
for (String word : bannedWords) {
    if (input.contains(word)) {
        System.out.println("不適切な言葉が含まれています: " + word);
        break;
    }
}

5-2. Analýza souborů logů (Detekce specifických zpráv)

Při analýze systémových nebo aplikačních logů můžete chtít extrahovat pouze řádky obsahující specifická klíčová slova jako ERROR nebo WARN.

List<String> logs = Arrays.asList(
    "[INFO] サーバーが起動しました",
    "[ERROR] データベース接続失敗",
    "[WARN] メモリ使用率が高い"
);

for (String log : logs) {
    if (log.contains("ERROR")) {
        System.out.println("エラー発生ログ: " + log);
    }
}

5-3. Filtrování řetězců v seznamu (Použití Stream API)

Při zpracování velkých datových sad použijte Stream API k extrakci pouze prvků obsahujících specifický podřetězec:

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. Parsování HTTP požadavkových hlaviček nebo URL

Ve webovém vývoji může směrování nebo zpracování specifické pro zařízení vyžadovat kontrolu podřetězců v User-Agent nebo 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. Kontrola cest k souborům nebo přípon

K určení typu souboru pomocí jeho cesty:

String filePath = "/usr/local/data/sample.csv";
if (filePath.contains(".csv")) {
    System.out.println("CSVファイルです。");
}

Poznámka:
Pro kontroly přípon souborů je často přesnější endsWith(".csv").

Praktické úvahy

  • Aplikujte normalizaci (např. toLowerCase(), trim()) když je vyžadována přesnost.
  • Pro data velkého rozsahu zvažte Stream API nebo regex.
  • Pamatujte, že contains() je částečná shoda—kombinujte s jinými podmínkami pro bezpečnější logiku.

6. Úvahy o výkonu

Zatímco metoda contains() nabízí vynikající čitelnost a jednoduchost, musíte zvážit její dopad na výkon při zpracování velkých datových sad nebo opakovaných operací.
Tato sekce vysvětluje náklady na zpracování contains() a alternativní přístupy pro zlepšení efektivity.

6-1. Interní chování a časová složitost contains()

Metoda contains() prohledává cílový řetězec sekvenčně od začátku k nalezení podřetězce.
Interně se spoléhá na metodu indexOf() a její nejhorší časová složitost je:

O(n * m)
– n = délka cílového řetězce
– m = délka hledaného řetězce

Příklad náročné zpracování:

for (String line : hugeTextList) {
    if (line.contains("error")) {
        // processing
    }
}

To může významně ovlivnit výkon při opakování v velkých smyčkách.

6-2. Techniky pro zlepšení výkonu při častých hledáních

Při opakovaném použití contains() ve velkých datových sadách mohou následující techniky zlepšit rychlost zpracování:

• Převeďte všechny řetězce na malá písmena předem

Místo volání toLowerCase() při každém porovnání normalizujte řetězce předem:

List<String> normalizedList = originalList.stream()
    .map(String::toLowerCase)
    .collect(Collectors.toList());
• Použijte Stream API s parallel() pro paralelní zpracování

Využijte jádra CPU ke zrychlení vyhledávání:

List<String> result = hugeTextList.parallelStream()
    .filter(line -> line.contains("keyword"))
    .collect(Collectors.toList());
• Použijte regulární výrazy pro složité vyhledávací vzory

Pokud jsou podmínky složité a lze je vyjádřit jedním regulárním výrazem, může být Pattern výkonnější:

Pattern pattern = Pattern.compile("error|fail|fatal");
for (String log : logs) {
    if (pattern.matcher(log).find()) {
        // matched
    }
}

6-3. Úvahy o efektivitě paměti a znovupoužitelnosti

Operace, které často převádějí řetězce — například toLowerCase() nebo substring() — mohou generovat mnoho zbytečných objektů řetězců, což ovlivňuje využití paměti.
To je zvláště důležité pro dlouho běžící aplikace nebo serverové zpracování.

Klíčové body:

  • Vyhněte se vytváření zbytečných instancí řetězců.
  • Pro velké datové sady zvažte bufferování nebo zpracování po částech.
  • Ukládání opakovaných výsledků contains() do mezipaměti může v některých případech zlepšit výkon.

7. Porovnání s jinými programovacími jazyky

Metoda contains() v Javě nabízí jednoduché, spolehlivé porovnávání podřetězců, ale jiné jazyky poskytují podobné funkce se svými vlastnostmi.
Tato sekce porovnává kontrolu podřetězců v Pythonu, JavaScriptu a C#, aby zdůraznila rozdíly a podobnosti.

7-1. Python: Jednoduchá částečná shoda s operátorem in

V Pythonu můžete kontrolovat zahrnutí podřetězce pomocí operátoru in:

text = "Hello, Python!"
if "Python" in text:
    print("含まれています")

Tato syntaxe je mimořádně čitelná — téměř jako přirozený jazyk — a vyžaduje minimální učení.

Rozdíly a poznámky:

  • in je jazykový operátor, ne metoda.
  • Python je také citlivý na velikost písmen při porovnávání řetězců.
  • None vyvolá výjimku; je nutná kontrola na null.

7-2. JavaScript: Částečná shoda s includes()

V JavaScriptu (ES6+) můžete použít metodu includes():

const text = "JavaScript is fun";
console.log(text.includes("fun")); // true

Tato metoda je velmi podobná contains() v Javě a snadno se mentálně přenáší.

Rozdíly a poznámky:

  • Předání undefined nevyvolá výjimku; jednoduše vrátí false.
  • includes() funguje také na polích, což zvyšuje jeho všestrannost.

7-3. C#: Contains() podobné Javě

C# také nabízí metodu Contains() s chováním podobným Javě:

string text = "Welcome to C#";
bool result = text.Contains("C#");

Rozdíly a poznámky:

  • Contains() v C# je ve výchozím nastavení citlivé na velikost písmen, ale můžete ignorovat velikost pomocí StringComparison.OrdinalIgnoreCase.
  • Předání null vyvolá ArgumentNullException.

7-4. Srovnávací tabulka napříč jazyky

LanguageExample SyntaxCase SensitivityNotes
Java"abc".contains("a")SensitiveThrows exception on null
Python"a" in "abc"SensitiveMost intuitive syntax
JavaScript"abc".includes("a")SensitiveAlso works for arrays
C#"abc".Contains("a")Sensitive (configurable)Comparison mode can be chosen

Shrnutí: Vyberte správnou syntaxi pro váš případ použití

Ačkoli kontrola podřetězců je běžnou požadavkou napříč jazyky, každý jazyk poskytuje vlastní metodu nebo syntaxi.
contains() v Javě nabízí stabilitu a přehlednost, což ji činí vhodnou pro podnikovou úroveň a udržovatelné aplikace.
Jazyky jako Python a JavaScript nabízejí jednodušší a stručnější syntaxi, což může být ideální pro lehké skripty nebo rychlé prototypování.

Porozuměním jak společným konceptům, tak specifickým vlastnostem každého jazyka budete schopni psát bezpečnější a efektivnější kód napříč různými jazyky.

8. Často kladené otázky (FAQ)

Níže jsou často kladené otázky týkající se metody contains() v Javě — pomáhají pochopit obtížné body a vyhnout se běžným úskalím.

Q1. Je contains() citlivé na velikost písmen?

Ano, je citlivé na velikost písmen.
Například "Java".contains("java") vrací false.

Řešení:

String input = "Welcome to Java";
boolean result = input.toLowerCase().contains("java");

Q2. Jak mohu kontrolovat částečné shody pomocí regulárních výrazů?

contains() nepodporuje regulární výrazy.
Použijte matches() nebo třídu Pattern.

Příklad (kontrola číselného vzoru):

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. Co se stane, když zavolám contains() na null?

Bude vyhozena výjimka NullPointerException.

String target = null;
System.out.println(target.contains("test")); // Error

Řešení:

if (target != null && target.contains("test")) {
    System.out.println("含まれています。");
}

Q4. Co se stane, když předám prázdný řetězec („“) do contains()?

Vždy vrátí true.

String text = "Java";
System.out.println(text.contains("")); // true

Ačkoliv je to součást oficiální specifikace, toto chování je zřídka užitečné a může způsobit neočekávané chyby, pokud prázdné řetězce nejsou zamýšlené.

Q5. Může contains() vyhledávat více klíčových slov najednou?

Ne. Každé volání kontroluje jen jedno klíčové slovo.

String text = "本日はシステムエラーが発生しました";
if (text.contains("エラー") || text.contains("障害") || text.contains("失敗")) {
    System.out.println("問題が検出されました。");
}

Dynamický přístup:

List<String> keywords = Arrays.asList("エラー", "障害", "失敗");
boolean found = keywords.stream().anyMatch(text::contains);

Q6. Kdy použít contains() vs indexOf()?

contains() vrací boolean, zatímco indexOf() vrací číselný index.

  • Použijte contains(), když chcete jen zjistit, zda podřetězec existuje.
  • Použijte indexOf(), když potřebujete také pozici.
    String text = "Error: Disk full";
    if (text.contains("Error")) {
        int pos = text.indexOf("Error");
        System.out.println("Position: " + pos);
    }
    

9. Závěr

Metoda contains() v Javě je výkonný a pohodlný nástroj pro určení, zda konkrétní podřetězec je obsažen v řetězci. Je široce používána v různých scénářích, jako je validace uživatelského vstupu, analýza logů a filtrování dat.

V tomto článku jsme pokryli:

  • Základní syntax a návratové hodnoty
  • Rozlišování velkých a malých písmen a jak s ním pracovat
  • Zpracování null a prázdných řetězců
  • Rozdíly od ostatních metod porovnávání řetězců
  • Praktické případy použití: validace, vyhledávání v logu, zpracování Stream
  • Úvahy o výkonu a optimalizační techniky
  • Porovnání s Pythonem, JavaScriptem a C#
  • Často kladené otázky a tipy na řešení problémů

Ačkoliv je contains() intuitivní a všestranný, jeho použití by mělo být pečlivě zváženo v případech zahrnujících velké datové sady, časté volání nebo komplexní podmínky vyhledávání. Kombinací normalizace, paralelního zpracování, regulárních výrazů a strategií cachování můžete zachovat jak výkon, tak čitelnost.

Protože contains() je základní pro práci s řetězci v Javě, doufáme, že vám tento článek pomůže používat jej bezpečněji a efektivněji ve vašich vývojových projektech.