Padroneggiare contains() in Java: Come eseguire ricerche di sottostringhe efficienti

目次

1. Introduzione: Perché la Ricerca di Stringhe è Importante in Java

La manipolazione delle stringhe è una delle operazioni più frequentemente utilizzate durante la programmazione in Java.
Sia che si tratti di controllare l’input dell’utente, analizzare i contenuti di un file o cercare parole chiave specifiche, spesso è necessario determinare se una particolare parola è contenuta in una data stringa.

Per soddisfare queste esigenze, Java fornisce un metodo comodo chiamato contains().
Con questo metodo, è possibile determinare facilmente se una stringa contiene parzialmente un’altra.
Ad esempio, se si vuole controllare se un messaggio di errore contiene una parola chiave specifica, contains() permette di farlo in una singola riga di codice.

Soprattutto in scenari che coinvolgono grandi volumi di testo—come applicazioni web, elaborazione di API o analisi di log—il metodo contains() migliora notevolmente la leggibilità e la manutenibilità del codice.
Tuttavia, ci sono anche considerazioni importanti come la sensibilità al caso e la possibilità di null.

Questo articolo spiega in dettaglio il metodo contains() di Java—dall’uso base e dagli errori comuni alle differenze con altri metodi e alle applicazioni pratiche.
Il nostro obiettivo è fornire informazioni utili non solo per i principianti ma anche per gli sviluppatori che utilizzano attivamente Java in progetti reali.

2. Sintassi Base e Caratteristiche del Metodo contains()

Il metodo contains() di Java determina se una stringa contiene parzialmente un’altra stringa.
La sua sintassi è molto semplice, ma è altamente pratica e utilizzata frequentemente nei compiti di programmazione quotidiani.

Sintassi Base

boolean result = targetString.contains(searchString);

Il metodo appartiene alla classe String e accetta un CharSequence (comunemente una String) come argomento.
Il suo valore di ritorno è boolean: true se la stringa target contiene la sottostringa data, e false altrimenti.

Codice di Esempio

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

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

Nell’esempio sopra, la sottostringa "programming" è presente nella stringa target, quindi contains() restituisce true.

Caratteristiche del Metodo

  • Controlla solo per corrispondenza parziale: Se hai bisogno di una corrispondenza esatta, usa equals() invece.
  • Sensibile al caso: Ad esempio, "Java" e "java" sono trattati come diversi (dettagli spiegati più avanti).
  • Non supporta espressioni regolari: Perché controlla semplicemente la presenza di una stringa, la corrispondenza di pattern richiede matches() o la classe Pattern.

Comportamento Quando si Passa null

Passare null a contains() attiva una NullPointerException.
Ad esempio, il seguente codice genererà un’eccezione:

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

Allo stesso modo, se la stringa target stessa è null, verrà generata la stessa eccezione.
Quindi, è altamente raccomandato effettuare controlli di null prima di chiamare contains().

3. Esempi di Utilizzo Pratico e Considerazioni Importanti

Il metodo contains() di Java è molto intuitivo e comodo, ma un uso scorretto può portare a bug inaspettati o codice inefficiente.
Questa sezione spiega l’uso base di contains() insieme ai punti chiave di cui essere consapevoli.

3-1. Esempio di Utilizzo Base

Il seguente codice dimostra un semplice esempio di controllo se la stringa target contiene una parola chiave specifica:

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

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

Come mostrato, contains() è frequentemente combinato con istruzioni if per eseguire ramificazioni condizionali.

3-2. Sensibilità al Caso

Il metodo contains() è sensibile al caso.
Ad esempio, il seguente codice restituisce false:

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

In questi casi, è comune convertire le stringhe in minuscolo (o maiuscolo) prima del confronto:

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

Questo approccio aiuta a eliminare le differenze di maiuscole/minuscole nell’input (ad esempio, l’input dell’utente).

3-3. Gestione di null e Stringhe Vuote

Una delle considerazioni più importanti quando si usa contains() è la gestione di null.
Se la stringa di destinazione o l’argomento è null, si verificherà una NullPointerException.

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

Per evitare questo problema, aggiungi sempre un controllo su null:

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

Nota anche:
Passare una stringa vuota ("") restituisce sempre true.

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

Tuttavia, questo comportamento è raramente utile nella pratica e può portare involontariamente a bug se le stringhe vuote vengono passate inavvertitamente.

3-4. Non Supporta Ricerche con più Parole Chiave

contains() può verificare solo una parola chiave alla volta.
Per verificare più parole chiave, è necessario chiamare contains() più volte o utilizzare l’API Stream.

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

Oppure, per insiemi di parole chiave dinamici:

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

4. Metodi Spesso Confrontati con contains()

Java fornisce diversi metodi per confrontare stringhe o verificare se esiste una sottostringa specifica.
Tra questi, contains() è usato per “corrispondenza parziale”, ma altri metodi servono a scopi simili.
Questa sezione spiega le caratteristiche e le differenze di tali metodi per aiutarti a usarli in modo appropriato.

4-1. Differenza da equals(): Corrispondenza Esatta vs. Corrispondenza Parziale

equals() determina se due stringhe sono esattamente identiche.
Al contrario, contains() verifica le corrispondenze parziali.

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

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

Principali differenze:

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

Linee Guida d’Uso:
Usa equals() quando i valori devono corrispondere esattamente (ad esempio, verifica ID).
Usa contains() quando le corrispondenze parziali sono accettabili (ad esempio, ricerca di parole chiave).

4-2. Differenza da indexOf(): Se Hai Bisogno della Posizione

Il metodo indexOf() può anche essere usato per verificare se una sottostringa esiste all’interno di una stringa.
La differenza è che indexOf() restituisce l’indice di inizio della sottostringa se trovata.
Se la sottostringa non è trovata, restituisce -1.

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

Puoi anche usare indexOf() per replicare il comportamento di contains():

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

Linee Guida d’Uso:
Se non hai bisogno dell’indice, contains() è più leggibile e preferibile.

4-3. Differenza da matches(): Supporto per le Espressioni Regolari

Il metodo matches() verifica se una stringa corrisponde completamente a una data espressione regolare.
Al contrario, contains() verifica solo corrispondenze di sottostringhe letterali e non supporta le regex.

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

Se desideri una corrispondenza parziale basata su regex, usa la classe Pattern:

4-4. Riepilogo del Confronto delle Funzionalità

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. Casi d’Uso Comuni e Codice di Esempio

Java’s contains() method is simple yet widely used in real development scenarios.
Typical use cases include user input validation, log analysis, and filtering operations.
This section covers practical examples with corresponding code.

5-1. Convalida dell’Input Utente (Rilevamento di Parole Proibite)

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. Analisi dei File di Log (Rilevamento di Messaggi Specifici)

When analyzing system or application logs, you may want to extract only lines containing specific keywords like ERROR or WARN.

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

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

5-3. Filtrare Stringhe in una Lista (Usando Stream API)

When handling large datasets, use the Stream API to extract only elements containing a specific substring:

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. Analisi degli Header HTTP o degli URL

In web development, routing or device-specific handling may require checking substrings in the User-Agent or 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. Controllo di Percorsi o Estensioni di File

To determine the type of a file using its path:

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

Nota:
For file extension checks, endsWith(".csv") is often more accurate.

Considerazioni Pratiche

  • Applica la normalizzazione (es. toLowerCase(), trim()) quando è richiesta precisione.
  • Per dati su larga scala, considera Stream API o regex.
  • Ricorda che contains() è una corrispondenza parziale—combinalo con altre condizioni per una logica più sicura.

6. Considerazioni sulle Prestazioni

While the contains() method offers excellent readability and simplicity, you must consider its performance impact when handling large datasets or running repeated operations.
This section explains the processing cost of contains() and alternative approaches for improved efficiency.

6-1. Comportamento Interno e Complessità Temporale di contains()

The contains() method searches the target string sequentially from the beginning to locate the substring.
Internally, it relies on the indexOf() method, and its worst-case time complexity is:

O(n * m)
– n = lunghezza della stringa target
– m = lunghezza della stringa di ricerca

Example of heavy processing:

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

This can significantly affect performance when repeated within large loops.

6-2. Tecniche per Migliorare le Prestazioni Durante Ricerche Frequenti

When using contains() repeatedly in large datasets, the following techniques can improve processing speed:

• Converti tutte le stringhe in minuscolo in anticipo

Instead of calling toLowerCase() during each comparison, normalize the strings beforehand:

List<String> normalizedList = originalList.stream()
    .map(String::toLowerCase)
    .collect(Collectors.toList());
• Utilizza l’API Stream con parallel() per l’elaborazione parallela

Sfrutta i core della CPU per velocizzare le ricerche:

List<String> result = hugeTextList.parallelStream()
    .filter(line -> line.contains("keyword"))
    .collect(Collectors.toList());
• Usa le espressioni regolari per modelli di ricerca complessi

Se le condizioni sono complesse e possono essere espresse in una singola regex, Pattern può offrire prestazioni migliori:

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

6-3. Considerazioni sull’Efficienza della Memoria e Riutilizzabilità

Le operazioni che convertono frequentemente le stringhe — come toLowerCase() o substring() — possono generare molti oggetti stringa inutili, influenzando l’uso della memoria.
Ciò è particolarmente importante per applicazioni a lungo termine o per l’elaborazione lato server.

Punti chiave:

  • Evita di creare istanze di stringa non necessarie.
  • Per grandi set di dati, considera il buffering o l’elaborazione a blocchi.
  • La memorizzazione nella cache dei risultati ripetuti di contains() può migliorare le prestazioni in alcuni casi.

7. Confronto con Altri Linguaggi di Programmazione

Il metodo contains() di Java offre un semplice e affidabile confronto di sottostringhe, ma altri linguaggi forniscono funzionalità simili con le proprie caratteristiche.
Questa sezione confronta il controllo delle sottostringhe in Python, JavaScript e C# per evidenziare differenze e somiglianze.

7-1. Python: Corrispondenza Parziale Semplice con l’Operatore in

In Python, è possibile verificare l’inclusione di una sottostringa usando l’operatore in:

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

Questa sintassi è estremamente leggibile — quasi come il linguaggio naturale — e richiede un apprendimento minimo.

Differenze e Note:

  • in è un operatore del linguaggio, non un metodo.
  • Python è anche sensibile al maiuscolo/minuscolo per il confronto di stringhe.
  • None genera un’eccezione; è necessario verificare la nullità.

7-2. JavaScript: Corrispondenza Parziale con includes()

In JavaScript (ES6+), è possibile utilizzare il metodo includes():

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

Questo metodo è molto simile al contains() di Java ed è facile da migrare mentalmente.

Differenze e Note:

  • Passare undefined non genera un’eccezione; restituisce semplicemente false.
  • includes() funziona anche sugli array, aumentando la sua versatilità.

7-3. C#: Contains() Simile a Java

C# offre anche un metodo Contains() con un comportamento simile a Java:

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

Differenze e Note:

  • Contains() di C# è sensibile al maiuscolo/minuscolo per impostazione predefinita, ma è possibile ignorare il case usando StringComparison.OrdinalIgnoreCase.
  • Passare null genera ArgumentNullException.

7-4. Tabella di Confronto tra i Linguaggi

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

Riepilogo: Scegli la Sintassi Giusta per il Tuo Caso d’Uso

Sebbene il controllo delle sottostringhe sia una necessità comune tra i linguaggi, ciascun linguaggio fornisce il proprio metodo o sintassi.
Il contains() di Java offre stabilità e chiarezza, rendendolo adatto ai sistemi enterprise e alle applicazioni manutenibili.
Linguaggi come Python e JavaScript offrono una sintassi più semplice e concisa, ideale per script leggeri o prototipi rapidi.

Comprendendo sia i concetti comuni sia le caratteristiche specifiche di ciascun linguaggio, sarai in grado di scrivere codice più sicuro ed efficiente su diversi linguaggi.

8. Domande Frequenti (FAQ)

Di seguito sono riportate le domande più frequenti sul metodo contains() di Java — per aiutarti a comprendere i punti critici e a evitare gli errori più comuni.

Q1. contains() è sensibile al maiuscolo/minuscolo?

Sì, è sensibile al maiuscolo/minuscolo.
Ad esempio, "Java".contains("java") restituisce false.

Soluzione:

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

Q2. Come posso verificare corrispondenze parziali usando le espressioni regolari?

contains() non supporta le espressioni regolari.
Usa matches() o la classe Pattern invece.

Esempio (verifica del pattern numerico):

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. Cosa succede se chiamo contains() su null?

Verrà lanciata una NullPointerException.

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

Soluzione:

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

Q4. Cosa succede se passo una stringa vuota (“”) a contains()?

Restituisce sempre true.

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

Sebbene faccia parte della specifica ufficiale, questo comportamento è raramente utile e può causare bug inaspettati se le stringhe vuote non sono previste.

Q5. contains() può cercare più parole chiave contemporaneamente?

No. Ogni chiamata controlla una sola parola chiave.

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

Approccio dinamico:

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

Q6. Quando dovrei usare contains() rispetto a indexOf()?

contains() restituisce un booleano, mentre indexOf() restituisce un indice numerico.

  • Usa contains() quando vuoi semplicemente sapere se la sottostringa esiste.
  • Usa indexOf() quando ti serve anche la posizione.
    String text = "Error: Disk full";
    if (text.contains("Error")) {
        int pos = text.indexOf("Error");
        System.out.println("Position: " + pos);
    }
    

9. Conclusione

Il metodo contains() di Java è uno strumento potente e comodo per determinare se una specifica sottostringa è contenuta in una stringa.
È ampiamente usato in vari scenari come la validazione dell’input dell’utente, l’analisi dei log e il filtraggio dei dati.

In questo articolo, abbiamo coperto:

  • Sintassi di base e valori di ritorno
  • Sensibilità al maiuscolo/minuscolo e come gestirla
  • Gestione di null e stringhe vuote
  • Differenze rispetto ad altri metodi di confronto di stringhe
  • Casi d’uso pratici: validazione, ricerca nei log, elaborazione di Stream
  • Considerazioni sulle prestazioni e tecniche di ottimizzazione
  • Confronto con Python, JavaScript e C#
  • Domande frequenti e consigli per la risoluzione dei problemi

Sebbene contains() sia intuitivo e versatile, il suo utilizzo dovrebbe essere valutato attentamente nei casi che coinvolgono grandi dataset, chiamate frequenti o condizioni di ricerca complesse.
Combinando normalizzazione, elaborazione parallela, regex e strategie di caching, è possibile mantenere sia le prestazioni sia la leggibilità.

Poiché contains() è fondamentale per lavorare con le stringhe in Java, speriamo che questo articolo ti aiuti a usarlo in modo più sicuro ed efficace nei tuoi progetti di sviluppo.