Dominando contains() em Java: Como Realizar Pesquisas de Substrings Eficientes

.

目次

1. Introdução: Por que a Busca de Strings é Importante em Java

A manipulação de strings é uma das operações mais frequentemente usadas ao programar em Java.
Seja verificando a entrada do usuário, analisando o conteúdo de arquivos ou procurando palavras‑chave específicas, você costuma precisar determinar se uma palavra particular está contida em uma determinada string.

Para atender a essas necessidades, o Java fornece um método conveniente chamado contains().
Com esse método, você pode determinar facilmente se uma string contém parcialmente outra.
Por exemplo, se quiser verificar se uma mensagem de erro contém uma palavra‑chave específica, contains() permite fazer isso em uma única linha de código.

Especialmente em cenários que envolvem grandes volumes de texto — como aplicações web, processamento de APIs ou análise de logs — o método contains() melhora consideravelmente a legibilidade e a manutenibilidade do código.
Entretanto, também existem considerações importantes, como sensibilidade a maiúsculas/minúsculas e a possibilidade de null.

Este artigo explica o método contains() do Java em detalhes — desde o uso básico e erros comuns até diferenças em relação a outros métodos e aplicações práticas.
Nosso objetivo é fornecer informações úteis não apenas para iniciantes, mas também para desenvolvedores que utilizam Java em projetos reais.

2. Sintaxe Básica e Características do Método contains()

O método contains() do Java determina se uma string contém parcialmente outra string.
Sua sintaxe é muito simples, porém é altamente prática e usada com frequência nas tarefas cotidianas de programação.

Sintaxe Básica

boolean result = targetString.contains(searchString);

O método pertence à classe String e aceita um CharSequence (geralmente um String) como argumento.
Seu valor de retorno é boolean: true se a string alvo contém a substring fornecida, e false caso contrário.

Código de Exemplo

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

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

No exemplo acima, a substring "programming" está presente na string alvo, portanto contains() retorna true.

Características do Método

  • Verifica apenas correspondência parcial: Se precisar de correspondência exata, use equals() em vez disso.
  • Sensível a maiúsculas/minúsculas: Por exemplo, "Java" e "java" são tratadas como diferentes (detalhes explicados adiante).
  • Não suporta expressões regulares: Como ele simplesmente verifica a presença de uma string, a correspondência de padrões requer matches() ou a classe Pattern.

Comportamento Quando null É Passado

Passar null para contains() dispara uma NullPointerException.
Por exemplo, o código a seguir lançará uma exceção:

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

Da mesma forma, se a própria string alvo for null, a mesma exceção será lançada.
Portanto, recomenda‑se fortemente realizar verificações de null antes de chamar contains().

3. Exemplos Práticos de Uso e Considerações Importantes

O método contains() do Java é muito intuitivo e conveniente, mas o uso incorreto pode gerar bugs inesperados ou código ineficiente.
Esta seção explica o uso básico de contains() juntamente com os pontos chave que você deve observar.

3-1. Exemplo de Uso Básico

O código a seguir demonstra um exemplo simples de verificação se a string alvo contém uma palavra‑chave específica:

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

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

Como mostrado, contains() é frequentemente combinado com instruções if para realizar ramificações condicionais.

3-2. Sensibilidade a Maiúsculas/Minúsculas

O método contains() é sensível a maiúsculas/minúsculas.
Por exemplo, o código a seguir retorna false:

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

.Nesses casos, é comum converter as strings para minúsculas (ou maiúsculas) antes da comparação:

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

Essa abordagem ajuda a eliminar diferenças de capitalização na entrada (por exemplo, entrada do usuário).

3-3. Tratamento de null e Strings Vazias

Uma das considerações mais importantes ao usar contains() é o tratamento de null.
Se a string alvo ou o argumento for null, ocorrerá um NullPointerException.

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

Para evitar esse problema, sempre adicione uma verificação de null:

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

Observe também: passar uma string vazia ("") sempre retorna true.

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

Entretanto, esse comportamento raramente é útil na prática e pode levar a bugs inesperados se strings vazias forem passadas inadvertidamente.

3-4. Não Suporta Busca por Múltiplas Palavras‑Chave

contains() pode verificar apenas uma palavra‑chave por vez.
Para verificar múltiplas palavras‑chave, você deve chamar contains() várias vezes ou usar a Stream API.

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

Ou, para conjuntos de palavras‑chave dinâmicos:

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

4. Métodos Frequentemente Comparados com contains()

O Java oferece vários métodos para comparar strings ou verificar se uma substring específica existe. Dentre eles, contains() é usado para “correspondência parcial”, mas outros métodos também atendem a propósitos semelhantes. Esta seção explica as características e diferenças desses métodos para ajudá‑lo a usá‑los adequadamente.

4-1. Diferença em relação ao equals(): Correspondência Exata vs. Parcial

equals() determina se duas strings são exatamente idênticas. Em contraste, contains() verifica correspondências parciais.

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

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

Principais diferenças:

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

Diretriz de Uso: Use equals() quando os valores precisam coincidir exatamente (por exemplo, verificação de ID). Use contains() quando correspondências parciais são aceitáveis (por exemplo, busca por palavra‑chave).

4-2. Diferença em relação ao indexOf(): Necessidade da Posição

O método indexOf() também pode ser usado para verificar se uma substring existe dentro de uma string. A diferença é que indexOf() retorna o índice inicial da substring se encontrada. Se a substring não for encontrada, ele retorna -1.

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

Você também pode usar indexOf() para replicar o comportamento de contains():

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

Diretriz de uso: Se você não precisa do índice, contains() é mais legível e preferível.

4-3. Diferença em relação ao matches(): Suporte a Expressões Regulares

O método matches() verifica se uma string corresponde totalmente a uma expressão regular fornecida. Em contraste, contains() verifica apenas correspondências literais de substring e não suporta regex.

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

Se você quiser correspondência parcial baseada em regex, use a classe Pattern:

4-4. Resumo da Comparação de Recursos

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. Casos de Uso Comuns e Código de Exemplo

O método contains() do Java é simples, mas amplamente utilizado em cenários de desenvolvimento reais.
Casos de uso típicos incluem validação de entrada do usuário, análise de logs e operações de filtragem.
Esta seção cobre exemplos práticos com código correspondente.

5-1. Validação de Entrada do Usuário (Detecção de Palavras Proibidas)

Em formulários ou aplicativos de chat, você pode precisar detectar se certas palavras proibidas estão incluídas.

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

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

Tratando múltiplas palavras NG:

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

5-2. Análise de Arquivos de Log (Detecção de Mensagens Específicas)

Ao analisar logs de sistema ou aplicação, você pode querer extrair apenas linhas contendo palavras-chave específicas como ERROR ou WARN.

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

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

5-3. Filtragem de Strings em uma Lista (Usando Stream API)

Ao lidar com grandes conjuntos de dados, use a Stream API para extrair apenas elementos contendo uma subcadeia específica:

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. Análise de Cabeçalhos de Requisição HTTP ou URLs

No desenvolvimento web, roteamento ou manipulação específica de dispositivos pode exigir verificação de subcadeias no User-Agent ou 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. Verificação de Caminhos de Arquivos ou Extensões

Para determinar o tipo de um arquivo usando seu caminho:

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

Nota:
Para verificações de extensão de arquivo, endsWith(".csv") é frequentemente mais preciso.

Considerações Práticas

  • Aplique normalização (ex.: toLowerCase(), trim()) quando a precisão for necessária.
  • Para dados em grande escala, considere Stream API ou regex.
  • Lembre-se de que contains() é uma correspondência parcial — combine com outras condições para uma lógica mais segura.

6. Considerações de Desempenho

Embora o método contains() ofereça excelente legibilidade e simplicidade, você deve considerar seu impacto no desempenho ao lidar com grandes conjuntos de dados ou executar operações repetidas.
Esta seção explica o custo de processamento do contains() e abordagens alternativas para maior eficiência.

6-1. Comportamento Interno e Complexidade de Tempo do contains()

O método contains() pesquisa a string de destino sequencialmente a partir do início para localizar a subcadeia.
Internamente, ele se baseia no método indexOf(), e sua complexidade de tempo no pior caso é:

O(n * m)
– n = comprimento da string de destino
– m = comprimento da string de pesquisa

Exemplo de processamento pesado:

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

Isso pode afetar significativamente o desempenho quando repetido em loops grandes.

6-2. Técnicas para Melhorar o Desempenho Durante Buscas Frequentes

Ao usar contains() repetidamente em grandes conjuntos de dados, as seguintes técnicas podem melhorar a velocidade de processamento:

• Converta todas as strings para minúsculas com antecedência

Em vez de chamar toLowerCase() durante cada comparação, normalize as strings previamente:

List<String> normalizedList = originalList.stream()
    .map(String::toLowerCase)
    .collect(Collectors.toList());

.##### • Use a API Stream com parallel() para processamento paralelo

Utilize os núcleos da CPU para acelerar as buscas:

List<String> result = hugeTextList.parallelStream()
    .filter(line -> line.contains("keyword"))
    .collect(Collectors.toList());
• Use expressões regulares para padrões de busca complexos

Se as condições forem complexas e puderem ser expressas em uma única regex, Pattern pode ter um desempenho melhor:

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

6-3. Considerações sobre Eficiência de Memória e Reutilização

Operações que convertem strings com frequência — como toLowerCase() ou substring() — podem gerar muitos objetos de string desnecessários, afetando o uso de memória.
Isso é particularmente importante para aplicações de longa duração ou processamento no lado do servidor.

Pontos principais:

  • Evite criar instâncias de string desnecessárias.
  • Para grandes volumes de dados, considere o uso de buffers ou processamento em blocos.
  • Cachear resultados repetidos de contains() pode melhorar o desempenho em certos casos.

7. Comparação com Outras Linguagens de Programação

O método contains() do Java oferece correspondência de substrings simples e confiável, mas outras linguagens fornecem recursos semelhantes com suas próprias características.
Esta seção compara a verificação de substrings em Python, JavaScript e C# para destacar diferenças e semelhanças.

7-1. Python: Correspondência Parcial Simples com o Operador in

Em Python, você pode verificar a inclusão de substrings usando o operador in:

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

Essa sintaxe é extremamente legível — quase como linguagem natural — e requer aprendizado mínimo.

Diferenças e Observações:

  • in é um operador da linguagem, não um método.
  • Python também diferencia maiúsculas de minúsculas na comparação de strings.
  • None gera uma exceção; verificações de nulidade são necessárias.

7-2. JavaScript: Correspondência Parcial com includes()

Em JavaScript (ES6+), você pode usar o método includes():

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

Esse método é muito semelhante ao contains() do Java e fácil de migrar mentalmente.

Diferenças e Observações:

  • Passar undefined não lança exceção; simplesmente retorna false.
  • includes() também funciona em arrays, aumentando sua versatilidade.

7-3. C#: Contains() Similar ao Java

C# também oferece um método Contains() com comportamento semelhante ao Java:

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

Diferenças e Observações:

  • Contains() em C# diferencia maiúsculas de minúsculas por padrão, mas você pode ignorar a diferença usando StringComparison.OrdinalIgnoreCase.
  • Passar null dispara ArgumentNullException.

7-4. Tabela de Comparação entre Linguagens

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

Resumo: Escolha a Sintaxe Adequada para Seu Caso de Uso

Embora a verificação de substrings seja uma necessidade comum entre as linguagens, cada uma fornece seu próprio método ou sintaxe.
O contains() do Java oferece estabilidade e clareza, sendo bem adequado para sistemas corporativos e aplicações de manutenção facilitada.
Linguagens como Python e JavaScript oferecem sintaxes mais simples e concisas, que podem ser ideais para scripts leves ou prototipagem rápida.

Ao compreender tanto os conceitos comuns quanto as características específicas de cada linguagem, você poderá escrever código mais seguro e eficiente em diferentes ambientes.

8. Perguntas Frequentes (FAQ)

A seguir, perguntas comuns sobre o método contains() do Java — ajudando você a entender pontos críticos e evitar armadilhas frequentes.

Q1. O contains() diferencia maiúsculas de minúsculas?

Sim, ele diferencia maiúsculas de minúsculas.
Por exemplo, "Java".contains("java") retorna false.

Solução:

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

Q2. Como posso verificar correspondências parciais usando expressões regulares?

contains() não suporta expressões regulares.
Use matches() ou a classe Pattern em vez disso.

Exemplo (verificando padrão numérico):

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. O que acontece se eu chamar contains() em null?

Uma NullPointerException será lançada.

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

Solução:

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

Q4. O que acontece se eu passar uma string vazia (“”) para contains()?

Sempre retorna true.

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

Embora faça parte da especificação oficial, esse comportamento raramente é útil e pode causar bugs inesperados se strings vazias não forem intencionais.

Q5. O contains() pode buscar múltiplas palavras‑chave de uma vez?

Não. Cada chamada verifica apenas uma palavra‑chave.

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

Abordagem dinâmica:

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

Q6. Quando devo usar contains() vs indexOf()?

contains() retorna um boolean, enquanto indexOf() retorna um índice numérico.

  • Use contains() quando você simplesmente quer saber se a substring existe.
  • Use indexOf() quando também precisa da posição.
    String text = "Error: Disk full";
    if (text.contains("Error")) {
        int pos = text.indexOf("Error");
        System.out.println("Position: " + pos);
    }
    

9. Conclusão

O método contains() do Java é uma ferramenta poderosa e conveniente para determinar se uma substring específica está contida em uma string.
É amplamente usado em diversos cenários, como validação de entrada de usuário, análise de logs e filtragem de dados.

Neste artigo, abordamos:

  • Sintaxe básica e valores de retorno
  • Sensibilidade a maiúsculas/minúsculas e como tratá‑la
  • Tratamento de nulls e strings vazias
  • Diferenças de outros métodos de comparação de strings
  • Casos de uso práticos: validação, busca em logs, processamento com Stream
  • Considerações de desempenho e técnicas de otimização
  • Comparação com Python, JavaScript e C#
  • Perguntas frequentes e dicas de solução de problemas

Embora contains() seja intuitivo e versátil, seu uso deve ser cuidadosamente avaliado em casos que envolvem grandes conjuntos de dados, chamadas frequentes ou condições de busca complexas.
Ao combinar normalização, processamento paralelo, regex e estratégias de cache, você pode manter tanto o desempenho quanto a legibilidade.

Como contains() é fundamental para trabalhar com strings em Java, esperamos que este artigo ajude você a usá‑lo de forma mais segura e eficaz em seus projetos de desenvolvimento.