Comparação de strings em Java explicada completamente | Diferenças e uso de ==, equals e compareTo

目次

1. Introdução

Qual é a importância de comparar strings em Java?

Na programação em Java, há muitas situações em que lidamos com strings (String). Verificações de nomes de usuário, correspondência de valores de entrada de formulários, confirmação de respostas de API e assim por diante, a comparação de strings é exigida em todos os tipos de cenários.

Nesse momento, “como comparar strings corretamente” é um ponto surpreendentemente fácil de tropeçar para iniciantes. Em particular, se você não entender a diferença entre o operador == e o método equals(), isso pode causar bugs que levam a resultados inesperados.

É perigoso não entender a diferença entre “==” e “equals”

Por exemplo, observe o código a seguir.

String a = "apple";
String b = new String("apple");

System.out.println(a == b);       // 結果: false
System.out.println(a.equals(b));  // 結果: true

Muitos ficarão surpresos com o resultado de saída deste código. Mesmo sendo a mesma string, == retorna false, enquanto equals() retorna true. Isso ocorre porque o Java trata as strings como “tipo de referência”, e == compara os endereços de referência.

Dessa forma, comparar strings corretamente está diretamente relacionado à confiabilidade e legibilidade do programa. Por outro lado, entender o método correto permite prevenir bugs antes que eles ocorram.

O que você pode aprender neste artigo

Neste artigo, explicaremos de forma detalhada os métodos de comparação de strings em Java, desde o básico até o avançado. Responderemos a dúvidas como as seguintes, explicando de maneira estruturada e fácil de entender para iniciantes.

  • Qual é a diferença entre == e equals()?
  • Como comparar ignorando maiúsculas e minúsculas?
  • Como comparar strings em ordem lexicográfica?
  • Como evitar exceções ao comparar com null?

Com exemplos de código úteis na prática, vamos adquirir firmemente o conhecimento correto de comparação de strings.

2. Os básicos das strings em Java

A string é um “tipo de referência”

Em Java, o tipo String não é um tipo primitivo (como int ou boolean), mas um “tipo de referência (Reference Type)”. Isso significa que a variável String não contém os dados da string em si, mas faz referência a um objeto de string que existe na memória heap.

Em outras palavras, ao escrever algo como o seguinte:

String a = "hello";
String b = "hello";

a e b referenciam a mesma string "hello", então a == b pode retornar true. No entanto, isso é devido ao mecanismo de otimização de literais de string (String Interning) do Java.

A diferença entre literais de string e new String()

Em Java, quando o mesmo literal de string é usado várias vezes, eles são otimizados para a mesma referência. Isso é uma funcionalidade do Java para compartilhar strings em tempo de execução e melhorar a eficiência da memória.

String s1 = "apple";
String s2 = "apple";
System.out.println(s1 == s2); // true(同じリテラルなので同一参照)

Por outro lado, ao usar a palavra-chave new para criar explicitamente um objeto, uma nova referência é criada.

String s3 = new String("apple");
System.out.println(s1 == s3); // false(異なる参照)
System.out.println(s1.equals(s3)); // true(内容は同じ)

Dessa forma, == verifica a igualdade de referências, enquanto equals() confirma a igualdade de conteúdo, tornando seus usos muito diferentes.

String é uma classe “imutável (immutable)”

Outra característica importante é que String é imutável (immutable). Ou seja, o conteúdo de um objeto String criado uma vez não pode ser alterado.

Por exemplo, ao escrever o seguinte:

String original = "hello";
original = original + " world";

Isso parece adicionar uma string ao original original, mas na verdade, um novo objeto String é criado e atribuído a original.

Graças a essa imutabilidade, String é thread-safe e útil para segurança e otimização de cache.

3. Métodos de comparação de strings

Comparação de referência com o operador ==

== compara as referências (endereços) dos objetos de string. Ou seja, mesmo que o conteúdo seja o mesmo, se forem objetos diferentes, retorna false.

String a = "Java";
String b = new String("Java");

System.out.println(a == b);        // false

Neste exemplo, a é um literal e b é criado com new, então as referências são diferentes e resulta em false. Não deve ser usado para comparação de conteúdo, então tome cuidado.

Comparação de conteúdo com o método equals()

equals() é o método correto para comparar o conteúdo das strings. É recomendado usá-lo na maioria das situações.

String a = "Java";
String b = new String("Java");

System.out.println(a.equals(b));   // true

Dessa forma, mesmo que as referências sejam diferentes, se o conteúdo for o mesmo, retorna true.

Pontos de atenção ao comparar com null

Código como o seguinte pode causar NullPointerException.

String input = null;
System.out.println(input.equals("test")); // 例外発生!

Para evitar isso, é recomendado escrever na forma constante.equals(variável).

System.out.println("test".equals(input)); // false(安全)

Comparação ignorando maiúsculas e minúsculas com o método equalsIgnoreCase()

Para comparações que não distinguem maiúsculas e minúsculas, como nomes de usuário ou endereços de e-mail, equalsIgnoreCase() é conveniente.

String a = "Hello";
String b = "hello";

System.out.println(a.equalsIgnoreCase(b)); // true

No entanto, em alguns casos especiais no Unicode (como o “İ” do turco), pode haver comportamentos inesperados, então é necessário cuidado adicional em aplicações internacionalizadas.

Comparação lexicográfica com o método compareTo()

compareTo() compara duas strings em ordem lexicográfica e retorna um inteiro como o seguinte.

  • 0: iguais
  • Valor negativo: a string do chamador vem antes (menor)
  • Valor positivo: a string do chamador vem depois (maior)
    String a = "apple";
    String b = "banana";
    
    System.out.println(a.compareTo(b)); // 負の値("apple"は"banana"より前)
    

É frequentemente usado em ordenação lexicográfica ou processamento de filtros, e é usado internamente em comparações de chaves como Collections.sort() ou TreeMap.

4. Exemplos práticos de uso

Verificação de entrada do usuário (função de login)

Uma das situações mais comuns é a verificação de correspondência de nomes de usuário ou senhas.

String inputUsername = "Naohiro";
String registeredUsername = "naohiro";

if (registeredUsername.equalsIgnoreCase(inputUsername)) {
    System.out.println("ログイン成功");
} else {
    System.out.println("ユーザー名が一致しません");
}

この例のように、大文字・小文字を無視して比較したい場面では equalsIgnoreCase() を使うのが適切です。

ただし、セキュリティ的にパスワード比較では大小文字を区別すべきなので、equals() を使いましょう。

Validação de Entrada (Processamento de Formulário)

例えば、ドロップダウンやテキストボックスからの入力値のチェックにも、文字列比較が使われます。

String selectedOption = request.getParameter("plan");

if ("premium".equals(selectedOption)) {
    System.out.println("プレミアムプランを選択しました。");
} else {
    System.out.println("その他のプランです。");
}

このように、nullチェックを兼ねた安全な比較として "定数".equals(変数) の形式が実務でよく使われます。ユーザー入力は必ずしも値が存在するとは限らないため、NullPointerExceptionを防ぐための書き方です。

Processamento de Ramificação com Múltiplas Condições (Uso semelhante ao switch)

複数の文字列候補を条件分岐で扱いたい場合は、equals()を連続して使うのが一般的です。

String cmd = args[0];

if ("start".equals(cmd)) {
    startApp();
} else if ("stop".equals(cmd)) {
    stopApp();
} else {
    System.out.println("コマンドが不正です");
}

Java 14以降では、文字列に対する switch 文も正式に使えるようになっています。

switch (cmd) {
    case "start":
        startApp();
        break;
    case "stop":
        stopApp();
        break;
    default:
        System.out.println("不明なコマンドです");
}

このように、文字列比較はロジックの分岐処理に直結するため、正確な理解が求められます。

Bugs causados por comparações com null e suas soluções

よくある失敗例として、null値との比較でアプリがクラッシュするケースがあります。

String keyword = null;

if (keyword.equals("検索")) {
    // 例外発生:java.lang.NullPointerException
}

このようなケースでは、次のように書くことで安全に比較できます。

if ("検索".equals(keyword)) {
    System.out.println("検索実行");
}

または、より厳密なnullチェックを先に行う方法もあります。

if (keyword != null && keyword.equals("検索")) {
    System.out.println("検索実行");
}

null安全なコードは堅牢性を高めるうえで必須のスキルです。

5. Desempenho e Otimização

Custo de Processamento na Comparação de Strings

equals()compareTo() は、一般に高速に動作するよう最適化されていますが、内部では1文字ずつ比較しているため、長い文字列や大量データを扱うときには影響が出ます。特に、ループの中で何度も同じ文字列と比較していると、意図しないパフォーマンス低下につながることがあります。

for (String item : items) {
    if (item.equals("keyword")) {
        // 比較回数が多い場合、注意
    }
}

Aceleração de Comparação com String.intern()

JavaのString.intern()メソッドを使うと、同じ内容の文字列をJVMの「文字列プール」に登録し、参照を共有することができます。これを利用すると、==での比較も可能になるため、性能上のメリットがある場合があります。

String a = new String("hello").intern();
String b = "hello";

System.out.println(a == b); // true

ただし、文字列プールを乱用するとヒープ領域が圧迫される可能性があるため、限られた用途での使用に留めるべきです。

Armadilhas do equalsIgnoreCase() e Alternativas

equalsIgnoreCase() は便利ですが、比較時に大文字・小文字を変換する処理が発生するため、通常のequals()よりも若干コストが高くなることがあります。性能がシビアな場面では、すでに大文字や小文字に統一した値で比較する方が高速です。

String input = userInput.toLowerCase();
if ("admin".equals(input)) {
    // 高速化された比較
}

このように事前に変換してからequals()を使うと、比較処理の効率を高められます。

Uso de StringBuilder / StringBuffer

大量の文字列連結が発生するようなケースでは、String を使っていると毎回新しいオブジェクトが生成され、メモリやCPUへの負荷が高くなります。比較処理が混在する場合も含め、連結や構築には StringBuilder を使い、比較には String のまま保持するのがベストプラクティスです。

StringBuilder sb = new StringBuilder();
sb.append("user_");
sb.append("123");

String result = sb.toString();

if (result.equals("user_123")) {
    // 比較処理
}

Design com Cache e Pré-processamento para Aceleração

同じ文字列との比較が何度も行われるような場合は、一度比較結果をキャッシュする、あるいはマップ(HashMapなど)を使って前処理することで、比較処理自体を減らすという手法も有効です。

Map<String, Runnable> commandMap = new HashMap<>();
commandMap.put("start", () -> startApp());
commandMap.put("stop", () -> stopApp());

Runnable action = commandMap.get(inputCommand);
if (action != null) {
    action.run();
}

このようにすれば、equals()による文字列比較は1回のMap検索に置き換わり、可読性とパフォーマンスの両方を向上させることができます。

6. Perguntas Frequentes (FAQ)

Q1. Qual a diferença entre == e equals()?

A.
==参照の比較(つまりメモリ上のアドレスの一致)を行います。一方でequals()は、文字列の中身(内容)を比較します。

String a = new String("abc");
String b = "abc";

System.out.println(a == b);        // false(参照が異なる)
System.out.println(a.equals(b));   // true(内容は同じ)

したがって、文字列の内容を比較したいときは必ずequals()を使用しましょう。

Q2. Por que usar equals() pode gerar erro devido a null?

A.
nullに対してメソッドを呼び出すと、NullPointerExceptionが発生するためです。

String input = null;
System.out.println(input.equals("test")); // 例外発生!

このエラーを防ぐには、次のように定数側から比較する書き方が安全です。

System.out.println("test".equals(input)); // false(安全)

Q3. Como comparar ignorando maiúsculas e minúsculas?

A.
Usando o método equalsIgnoreCase(), você pode comparar ignorando diferenças entre maiúsculas e minúsculas.

String a = "Hello";
String b = "hello";

System.out.println(a.equalsIgnoreCase(b)); // true

No entanto, com caracteres de largura total ou alguns caracteres Unicode especiais, o resultado pode ser inesperado, portanto, é preciso ter cuidado.

Q4. E se eu quiser comparar strings pela ordem?

A.
Quando você deseja investigar a ordem lexicográfica de strings, use compareTo().

String a = "apple";
String b = "banana";

System.out.println(a.compareTo(b)); // 負の値("apple"は"banana"より前)

Significado do valor de retorno:

  • 0 → Igual
  • Valor negativo → O lado esquerdo vem antes
  • Valor positivo → O lado esquerdo vem depois

É usado em processos de ordenação, etc.

Q5. Quais são as melhores práticas a lembrar ao comparar strings?

A.

  • Para comparação de conteúdo, sempre use equals()
  • Considere a segurança contra null e prefira a forma "constante".equals(variável)
  • Para ignorar maiúsculas/minúsculas, use equalsIgnoreCase() ou faça pré‑processamento com toLowerCase() / toUpperCase()
  • Em cenários que exigem comparações em massa ou alta performance, considere intern() ou design de cache
  • Mantenha sempre em mente o equilíbrio entre legibilidade e segurança

7. Conclusão

Em Java, é importante “usar corretamente” a comparação de strings

Ao longo deste artigo, explicamos de forma abrangente os fundamentos, a prática e o desempenho da comparação de strings em Java. Como String é um tipo de referência em Java, errar o método de comparação pode levar a comportamentos inesperados em várias situações.

Em particular, a diferença entre == e equals() é um ponto que costuma confundir iniciantes. Compreender e usar corretamente essa diferença é essencial para escrever código seguro e confiável.

O que você aprendeu neste artigo (Checklist)

  • == é um operador que compara referências (endereços de memória)
  • equals() é o método que compara o conteúdo da string (o mais seguro)
  • Usando equalsIgnoreCase() você pode ignorar maiúsculas e minúsculas
  • Com compareTo() é possível comparar strings lexicograficamente
  • A ordem "constante".equals(variável) permite comparação segura contra null
  • Para performance, intern() ou design de cache também são úteis

Conhecimento de comparação de strings que também é útil no trabalho

A comparação de strings está intrinsecamente ligada a tarefas de desenvolvimento diárias, como verificação de login, validação de entrada, buscas em banco de dados e estruturas condicionais. Possuir esse conhecimento permite prevenir bugs e garantir que o código se comporte conforme o esperado.

No futuro, ao escrever código que manipula strings, consulte este artigo e escolha o método de comparação adequado ao seu objetivo.