Java Concatenação
Concatenar é juntar textos, um atrás do outro: "Olá, " + "Ana" = "Olá, Ana". Você vai fazer isso o tempo todo para montar mensagens. Parece simples, e é, com uma pegadinha famosa: quando números entram na conta, o + às vezes soma e às vezes junta. Nesta aula você vai entender exatamente quando acontece cada coisa.
- Como juntar textos com
+e com+=. - O método
concate quando ele é diferente do+. - O que acontece quando você junta texto com números,
chareboolean, e por que"1" + 2 + 3dá123mas1 + 2 + "3"dá33. - Por que concatenar dentro de um laço pode ficar lento.
- Como juntar uma lista de textos com
String.join.
A ideia: emendar pedaços
Pense em vagões de trem: cada pedaço de texto é um vagão, e o + é o engate que prende um no outro. O trem resultante é um texto novo, com todos os vagões em ordem. Os vagões originais não mudam (lembre que Strings são imutáveis): a concatenação sempre cria uma String nova.
O operador +
Entre dois textos, o + não soma: ele emenda. Você já usou isso em System.out.println:
public class Main {
public static void main(String[] args) {
String nome = "Ana";
String sobrenome = "Souza";
System.out.println("Olá, " + nome + "!");
System.out.println(nome + sobrenome);
System.out.println(nome + " " + sobrenome);
String completo = nome + " " + sobrenome;
System.out.println(completo.length());
}
}
$ java Main.java Olá, Ana! AnaSouza « o + não coloca espaço sozinho Ana Souza « o espaço foi um pedaço a mais: " " 9
- "Olá, " + nome + "!"
- Três pedaços: um literal, uma variável e outro literal. Repare no espaço dentro das aspas depois da vírgula: é ele que separa "Olá," de "Ana".
- nome + sobrenome
- Emenda sem nada no meio:
AnaSouza. O Java nunca adivinha espaços. - String completo = …
- O resultado é uma String como qualquer outra: pode ser guardado, medido, comparado.
O erro mais comum de quem começa é a frase sair grudada: Olá,Ana ou Ana tem30anos. Os espaços precisam estar dentro das aspas: "Ana tem " + idade + " anos". Espaços fora das aspas (nome + sobrenome) são só formatação do código e não aparecem na saída.
Quebrar uma frase comprida no código
Quando o texto é longo demais para uma linha do editor, quebre-o em pedaços ligados por +. O javac junta tudo:
public class Main {
public static void main(String[] args) {
String mensagem = "Esta é uma frase bem comprida que não cabe "
+ "numa linha só do editor, então foi quebrada "
+ "em três pedaços.";
System.out.println(mensagem);
}
}
$ java Main.java Esta é uma frase bem comprida que não cabe numa linha só do editor, então foi quebrada em três pedaços.
Um literal entre aspas não pode ser quebrado no meio com Enter; por isso cada linha fecha as aspas e a próxima começa com +. Para textos de várias linhas de verdade, existe uma forma melhor: os Text Blocks.
Acrescentar no fim: +=
Você viu em Operadores de Atribuição que x += 5 é um atalho para x = x + 5. Com Strings funciona igual: frase += "texto" quer dizer frase = frase + "texto", ou seja, "cria uma String nova com o texto antigo mais o pedaço, e guarda de volta em frase".
public class Main {
public static void main(String[] args) {
String frase = "Eu gosto de";
frase = frase + " maçã";
frase += ", banana";
frase += " e uva";
System.out.println(frase);
int idade = 30;
String texto = "Idade: " + idade;
String soNumero = "" + idade;
String comValueOf = String.valueOf(idade);
System.out.println(texto);
System.out.println(soNumero.length() + " " + comValueOf.length());
}
}
$ java Main.java Eu gosto de maçã, banana e uva Idade: 30 2 2 « "30" virou um texto de 2 caracteres, pelos dois caminhos
As duas últimas variáveis mostram dois jeitos de transformar um número em texto: "" + idade (juntar com a String vazia, um truque muito usado) e String.valueOf(idade) ("valor de", a forma mais explícita). Os dois dão "30".
O método concat
Toda String tem o método concat, que faz a mesma emenda: a.concat(b) é parecido com a + b.
public class Main {
public static void main(String[] args) {
String nome = "Ana";
String completo = nome.concat(" Souza");
System.out.println(completo);
System.out.println("Bom".concat(" ").concat("dia"));
String nada = null;
System.out.println("Valor: " + nada);
System.out.println("Valor: ".concat(nada));
}
}
$ java Main.java Ana Souza Bom dia Valor: null Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.isEmpty()" because "str" is null at java.base/java.lang.String.concat(String.java:2961) at Main.main(Main.java:9)
As duas primeiras linhas funcionam como o +. A diferença aparece com null: o + escreve a palavra null e segue em frente; o concat derruba o programa. A mensagem fala de "str" porque esse é o nome do parâmetro dentro do método concat, na biblioteca do Java (a linha at java.base/java.lang.String.concat); a sua linha é a de baixo, Main.java:9.
+ | concat | |
|---|---|---|
Aceita números, char, boolean… | Sim, transforma em texto | Não: só String (erro de compilação) |
Com null | Escreve null | NullPointerException |
| Uso | O dia a dia | Raro |
Na prática, quase todo mundo usa o +. É bom conhecer o concat para entender código de outras pessoas.
Texto + número: soma ou emenda?
Aqui está a parte que mais confunde. O + tem dois trabalhos em Java:
- Se os dois lados são números, ele soma:
2 + 3é5. - Se pelo menos um lado é uma String, ele emenda, transformando o outro lado em texto:
"2" + 3é"23".
E a regra que decide tudo: o Java avalia o + da esquerda para a direita, um par de cada vez (veja Precedência). A cada passo, olha os dois lados daquele + e decide se soma ou emenda. Veja:
public class Main {
public static void main(String[] args) {
System.out.println("1" + 2 + 3);
System.out.println(1 + 2 + "3");
System.out.println(1 + 2 + "3" + 4 + 5);
System.out.println("Soma: " + 2 + 3);
System.out.println("Soma: " + (2 + 3));
System.out.println("Dobro: " + 2 * 3);
System.out.println('A' + 'B');
System.out.println("" + 'A' + 'B');
System.out.println('A' + "B");
System.out.println("Peso: " + 1.5 + " kg");
System.out.println("Aprovada? " + true);
}
}
$ java Main.java 123 33 3345 Soma: 23 Soma: 5 Dobro: 6 131 AB AB Peso: 1.5 kg Aprovada? true
Vamos passo a passo, como o Java faz:
| Expressão | Passo 1 | Passo 2 | Resultado |
|---|---|---|---|
"1" + 2 + 3 | "1" + 2 → texto + número → "12" | "12" + 3 → "123" | 123 |
1 + 2 + "3" | 1 + 2 → dois números → soma 3 | 3 + "3" → "33" | 33 |
1 + 2 + "3" + 4 + 5 | 1 + 2 → 3 | 3 + "3" → "33", depois "334", "3345" | 3345 |
"Soma: " + 2 + 3 | "Soma: " + 2 → "Soma: 2" | "Soma: 2" + 3 → "Soma: 23" | Soma: 23 (errado!) |
"Soma: " + (2 + 3) | Parênteses primeiro: 2 + 3 → 5 | "Soma: " + 5 | Soma: 5 |
"Dobro: " + 2 * 3 | * vem antes de +: 2 * 3 → 6 | "Dobro: " + 6 | Dobro: 6 |
Moral: quando quiser fazer uma conta dentro de uma frase, coloque a conta entre parênteses. *, / e % já vêm antes do +, mas os parênteses deixam claro para quem lê.
E o char?
Lembra que um char é, por dentro, um número (veja char e boolean)? Por isso 'A' + 'B' não dá "AB": são dois "números" (65 e 66), e o + soma: 131. Basta uma String na conta para virar emenda: "" + 'A' + 'B' e 'A' + "B" dão AB. Atenção às aspas: 'A' (simples) é char; "B" (duplas) é String.
Outros tipos
Qualquer valor pode ser emendado num texto: double vira 1.5 (com ponto, sempre; a vírgula do português só aparece com format e printf), boolean vira true/false, null vira null.
Missão: o programa deveria mostrar Soma: 5, mas mostra Soma: 23. Rode, veja o problema e corrija com parênteses.
public class Main {
public static void main(String[] args) {
int a = 2;
int b = 3;
System.out.println("Soma: " + a + b);
}
}
public class Main {
public static void main(String[] args) {
int a = 2;
int b = 3;
System.out.println("Soma: " + (a + b));
}
}
Brinque no JShell: antes de apertar Enter, tente adivinhar o resultado de "a" + 1 + 1, 1 + 1 + "a", 'a' + 1 e "" + 'a' + 1. Depois confira.
Concatenar dentro de um laço
Um laço repete um trecho de código várias vezes; você vai estudá-los em while e for. Aqui, o for repete a linha linha += i + " "; cinco vezes, com i valendo 1, 2, 3, 4 e 5:
public class Main {
public static void main(String[] args) {
String linha = "";
for (int i = 1; i <= 5; i++) {
linha += i + " ";
}
System.out.println(linha);
}
}
$ java Main.java 1 2 3 4 5
Funciona, e para poucas repetições está ótimo. O problema aparece quando são milhares. Como Strings são imutáveis, cada += cria uma String nova e copia tudo o que já existia. Na repetição número 10.000, o Java copia 10.000 caracteres só para acrescentar um. É como reescrever o caderno inteiro à mão cada vez que você quer acrescentar uma palavra no fim.
A solução é o StringBuilder ("construtor de Strings"), um "rascunho" que pode ser alterado, e que você vai estudar em StringBuilder. Só para ver a diferença, este programa junta 20.000 letras x dos dois jeitos e mede o tempo com System.nanoTime() (o relógio do computador, em bilionésimos de segundo):
public class Main {
public static void main(String[] args) {
int n = 20000;
long inicio = System.nanoTime();
String texto = "";
for (int i = 0; i < n; i++) {
texto += "x";
}
long tempoMais = (System.nanoTime() - inicio) / 1_000_000;
inicio = System.nanoTime();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
sb.append("x");
}
String texto2 = sb.toString();
long tempoSb = (System.nanoTime() - inicio) / 1_000_000;
System.out.println(texto.length() + " caracteres com +=: " + tempoMais + " ms");
System.out.println(texto2.length() + " caracteres com StringBuilder: " + tempoSb + " ms");
}
}
$ java Main.java 20000 caracteres com +=: 113 ms 20000 caracteres com StringBuilder: 2 ms
O resultado é o mesmo (20.000 caracteres), mas o += levou dezenas de vezes mais tempo. Os números mudam a cada execução e de computador para computador; a diferença, não. E ela cresce quanto maior o n, porque cada repetição do += copia um texto cada vez mais comprido.
+
Fora de laços, use + à vontade: numa linha como "Olá, " + nome + "!", o próprio Java já monta o texto de forma eficiente. A regra é só esta: dentro de um laço que repete muitas vezes, use StringBuilder.
Juntar uma lista: String.join
Quando você tem vários textos e quer juntá-los com um separador no meio (vírgula, espaço, barra), o String.join é mais limpo que uma fila de +. Ele cuida de colocar o separador só entre os itens, nunca sobrando no fim.
public class Main {
public static void main(String[] args) {
System.out.println(String.join(", ", "maçã", "banana", "uva"));
String nome = "Ana";
int idade = 30;
System.out.println(String.join(" ", "Nome:", nome, "| Idade:", String.valueOf(idade)));
System.out.println("Nome: %s | Idade: %d".formatted(nome, idade));
}
}
$ java Main.java maçã, banana, uva Nome: Ana | Idade: 30 Nome: Ana | Idade: 30
- String.join(", ", …)
- O primeiro argumento é o separador; os outros são os itens. Todos têm de ser Strings: por isso o número
idadepassou porString.valueOf. - "Nome: %s | Idade: %d".formatted(nome, idade)
- Uma terceira forma: um modelo com lugares marcados (
%spara texto,%dpara número inteiro) que são preenchidos em ordem. Para frases com muitos valores, costuma ser a mais legível. Ela tem aula própria: Formatar Texto.
Qual usar?
| Situação | Use | Exemplo |
|---|---|---|
| Montar uma frase com poucas partes | + | "Olá, " + nome + "!" |
| Acrescentar um pedaço a uma variável, poucas vezes | += | frase += " e uva"; |
| Conta dentro da frase | + com parênteses | "Total: " + (a + b) |
| Vários itens com separador | String.join | String.join(", ", itens) |
| Frase com muitos valores e formatação | formatted / String.format | "%s tem %d anos".formatted(nome, idade) |
| Juntar dentro de um laço longo | StringBuilder | veja StringBuilder |
| Número para texto | String.valueOf ou "" + n | String.valueOf(30) |
Quando dá errado
Soma: 23
O que aconteceu: o + trabalha da esquerda para a direita; depois de encontrar o texto, todos os + seguintes emendam.
Como resolver: parênteses em volta da conta: "Soma: " + (a + b).
error: ')' or ',' expected (esqueceu o +)
Este código tem um erro de propósito.
public class Main {
public static void main(String[] args) {
String nome = "Ana";
System.out.println("Olá, " nome);
}
}
$ javac Main.java
Main.java:4: error: ')' or ',' expected
System.out.println("Olá, " nome);
^
Main.java:4: error: not a statement
System.out.println("Olá, " nome);
^
Main.java:4: error: ';' expected
System.out.println("Olá, " nome);
^
3 errors
O que aconteceu: depois do texto "Olá, ", o javac esperava o fim dos parênteses ou uma vírgula, e encontrou nome. Os outros dois erros são consequência do primeiro.
Como resolver: coloque o + que falta: "Olá, " + nome.
error: incompatible types: int cannot be converted to String
Este código tem um erro de propósito.
public class Main {
public static void main(String[] args) {
String idade = 30;
System.out.println(idade);
}
}
$ javac Main.java
Main.java:3: error: incompatible types: int cannot be converted to String
String idade = 30;
^
1 error
O que aconteceu: o + transforma números em texto, mas a atribuição direta, não: 30 é um int e a variável é String.
Como resolver: String idade = "30";, String.valueOf(30) ou, se é um número, declare como int. O mesmo erro aparece com "Idade: ".concat(idade) quando idade é int, porque o concat só aceita String; nesse caso o javac ainda acrescenta a linha Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output ("algumas mensagens foram simplificadas").
error: bad operand types for binary operator '-'
Este código tem um erro de propósito.
public class Main {
public static void main(String[] args) {
System.out.println("Total: " + 5 - 2);
}
}
$ javac Main.java
Main.java:3: error: bad operand types for binary operator '-'
System.out.println("Total: " + 5 - 2);
^
first type: String
second type: int
1 error
O que aconteceu: + e - têm a mesma prioridade e são feitos da esquerda para a direita. Primeiro "Total: " + 5 virou o texto "Total: 5"; depois o Java tentou "Total: 5" - 2, e não existe "texto menos número" ("tipos de operandos inválidos para o operador '-'": o primeiro é String, o segundo é int).
Como resolver: "Total: " + (5 - 2).
null no meio
O que aconteceu: uma das variáveis valia null, e o + escreve a palavra null sem reclamar.
Como resolver: descubra por que a variável não recebeu valor (veja Strings, seção "String vazia × null").
Referência
| Forma | O que faz | Exemplo → resultado |
|---|---|---|
a + b | Emenda (se um dos lados é String) | "Ana" + " Souza" → "Ana Souza" |
s += x | s = s + x | s = "a"; s += "b"; → "ab" |
a.concat(b) | Emenda; só aceita String; quebra com null | "Bom".concat(" dia") → "Bom dia" |
"" + n | Número para texto | "" + 30 → "30" |
String.valueOf(x) | Qualquer valor para texto | String.valueOf(1.5) → "1.5" |
String.join(sep, …) | Junta com separador entre os itens | String.join("-", "a", "b") → "a-b" |
"…%s…".formatted(…) | Preenche um modelo | "Oi, %s".formatted("Ana") → "Oi, Ana" |
Exercícios
Missão final: usando as variáveis (sem escrever "Ana", "Souza", 30 ou 35 dentro de aspas), mostre exatamente:Ana Souza tem 30 anos e daqui a 5 anos terá 35.
Cuidado com os espaços e com a conta do 35.
public class Main {
public static void main(String[] args) {
String nome = "Ana";
String sobrenome = "Souza";
int idade = 30;
// escreva aqui
}
}
public class Main {
public static void main(String[] args) {
String nome = "Ana";
String sobrenome = "Souza";
int idade = 30;
System.out.println(nome + " " + sobrenome + " tem " + idade + " anos e daqui a 5 anos terá " + (idade + 5) + ".");
}
}
1. O resultado
O que System.out.println("5" + 5 + 5); mostra?
2. E agora?
O que System.out.println(5 + 5 + "5"); mostra?
3. Juntar com vírgulas
Complete para mostrar pão, leite, café:
4. O que System.out.println('x' + 'y'); mostra?
5. Você precisa juntar 50.000 linhas de um relatório dentro de um laço. O que usar?
6. Se String s = null;, o que System.out.println("Nome: " + s); faz?
Resumo
+entre textos emenda; os espaços têm de estar dentro das aspas.+=acrescenta no fim (cria uma String nova e guarda de volta).concatfaz o mesmo, mas só aceita String e quebra comnull; o+é o usado no dia a dia.- O
+trabalha da esquerda para a direita: dois números somam; com uma String no meio, emenda."1" + 2 + 3→123;1 + 2 + "3"→33. Contas dentro de frases vão entre parênteses. char + charsoma os códigos; para juntar letras, comece com"".- Em laços longos, use
StringBuilder; para listas com separador,String.join.