Java Text Blocks Java 15+

Escrever um texto de várias linhas com aspas comuns é sofrido: um \n no fim de cada linha, um + no começo da próxima, uma barra antes de cada aspa. O text block ("bloco de texto") resolve isso: você abre com três aspas, escreve o texto do jeito que ele deve sair, e fecha com três aspas.

Você vai aprender
  • Como escrever um text block com """ e as regras de abertura e fechamento.
  • Como o Java decide quanto da indentação é "margem" do código e quanto é parte do texto.
  • Como controlar a quebra no fim: o """ na linha de baixo ou colado no texto.
  • A barra \ no fim da linha (juntar linhas) e o \s (manter um espaço).
  • Como preencher um text block com valores usando formatted(), com exemplos de JSON e HTML.

Text blocks existem desde o Java 15 (2020). Em projetos presos ao Java 8 ou 11, a alternativa é a concatenação com \n, que você vai ver logo abaixo para comparar.


Antes e depois

A Ana quer guardar uma quadrinha numa variável. Com o que você aprendeu em Concatenação e Caracteres Especiais, seria assim (variável antigo). Com um text block, assim (variável novo):

public class Main {
    public static void main(String[] args) {
        String antigo = "Batatinha quando nasce\n"
                + "espalha a rama pelo chão\n"
                + "menininha quando dorme\n"
                + "põe a mão no coração\n";
        String novo = """
                Batatinha quando nasce
                espalha a rama pelo chão
                menininha quando dorme
                põe a mão no coração
                """;
        System.out.print(novo);
        System.out.println(antigo.equals(novo));
    }
}
$ java Main.java
Batatinha quando nasce
espalha a rama pelo chão
menininha quando dorme
põe a mão no coração
true       « as duas Strings são idênticas

O equals deu true: o text block é só outro jeito de escrever uma String. Depois de compilado, não há diferença nenhuma; todos os métodos de Métodos de String funcionam igual.

"""
Três aspas duplas abrem o bloco. Depois delas, nada na mesma linha: o texto começa na linha de baixo.
Batatinha quando nasce …
O conteúdo, escrito como deve aparecer. Cada Enter vira um \n.
"""; (na última linha)
Três aspas fecham o bloco. Como estão na linha de baixo, a última linha do texto também termina com \n.
System.out.print(novo)
Usamos print (sem "ln") porque o texto já termina com quebra de linha. Com println, apareceria uma linha em branco a mais.

A margem: quanto da indentação fica?

Repare que, no código, as linhas da quadrinha têm 16 espaços na frente (para ficarem alinhadas com o resto do programa), mas na saída não têm nenhum. O Java tirou esses espaços sozinho. Como ele sabe quais espaços tirar?

A regra: o Java olha todas as linhas do bloco, incluindo a linha do """ de fechamento, e acha a que está mais à esquerda. Essa linha define a margem. Os espaços até a margem são da "arrumação do código" (o nome técnico é indentação incidental) e são removidos de todas as linhas. O que passar da margem é parte do texto.

É como uma folha de caderno com a linha vermelha da margem: tudo que está à esquerda dela não conta; o que está à direita, conta, incluindo os recuos.

public class Main {
    public static void main(String[] args) {
        String a = """
                Ana
                  Bruno
                Carla
                """;
        String b = """
                Ana
                  Bruno
                Carla
            """;
        String c = """
                Ana
                  Bruno
                Carla""";
        System.out.print(a);
        System.out.println("---");
        System.out.print(b);
        System.out.println("---");
        System.out.print(c);
        System.out.println("|fim");
    }
}
$ java Main.java
Ana
  Bruno       « os 2 espaços a mais que a margem ficaram
Carla
---
    Ana       « o """ estava 4 espaços mais à esquerda: a margem recuou
      Bruno
    Carla
---
Ana
  Bruno
Carla|fim     « sem quebra no fim: o """ estava colado no texto
BlocoLinha mais à esquerdaResultado
aAna, Carla e o """, empatados (16 espaços)Margem em 16: Ana sem recuo, Bruno com 2 espaços.
bO """ de fechamento (12 espaços)Margem em 12: todas as linhas ganham 4 espaços na frente.
cAna e Carla (16)Igual ao a, mas sem a quebra de linha final, porque o """ está na mesma linha de Carla.

Ou seja, a posição do """ de fechamento é o seu "controle": alinhado com o texto, nenhum recuo extra; mais à esquerda, o texto inteiro ganha recuo; colado na última linha, sem quebra no fim.

Não misture tabs e espaços

A conta da margem é feita caractere por caractere: um tab conta como um caractere, igual a um espaço. Se umas linhas forem recuadas com tab e outras com espaços, o resultado fica estranho. Configure o editor para usar só espaços (as IDEs já fazem isso).

Missão: reescreva o cardápio como um text block. A saída deve continuar igual: o título sem recuo e cada item com dois espaços antes do traço.

public class Main {
    public static void main(String[] args) {
        String cardapio = "Cardápio do dia\n"
                + "  - Arroz\n"
                + "  - Feijão\n"
                + "  - Salada\n";
        System.out.print(cardapio);
    }
}
public class Main {
    public static void main(String[] args) {
        String cardapio = """
                Cardápio do dia
                  - Arroz
                  - Feijão
                  - Salada
                """;
        System.out.print(cardapio);
    }
}

Barra no fim da linha, \s, aspas e espaços

Dentro de um text block, as sequências de escape continuam funcionando, e há duas novidades:

public class Main {
    public static void main(String[] args) {
        String uma = """
                Esta frase é bem comprida, mas eu quero \
                que ela saia numa linha só.
                """;
        System.out.print(uma);
        String espacos = """
                nome:   
                nota:\s
                """;
        System.out.print(espacos.replace(" ", "·"));
        String aspas = """
                Ela disse "oi" e 'tchau'.
                Três aspas: \"""
                Tab:\tfim
                """;
        System.out.print(aspas);
    }
}
$ java Main.java
Esta frase é bem comprida, mas eu quero que ela saia numa linha só.
nome:          « os 3 espaços do fim da linha sumiram
nota:·         « o \s virou um espaço (trocado por · para ficar visível)
Ela disse "oi" e 'tchau'.
Três aspas: """
Tab:	fim
\ (no fim da linha)
Uma barra como último caractere da linha "cancela" a quebra: a linha de baixo continua na mesma linha do texto. Útil para frases longas que você quer quebrar só no código. Java 15+
espaços no fim da linha
O Java remove os espaços que sobram no fim de cada linha (muitos editores os deixam sem você perceber). A linha nome: virou nome:.
\s
Um espaço que não é removido (space). Use no fim da linha quando o espaço importa. Java 15+
"oi" e 'tchau'
Aspas simples e duplas não precisam de barra: o bloco só termina em três aspas seguidas.
\"""
Para ter três aspas dentro do texto, escape a primeira.
\t
Os escapes comuns (\t, \n, \\…) funcionam como nas Strings normais.

Preencher com valores: formatted()

Text blocks são ótimos como modelos: um texto fixo com "buracos" a preencher. Os buracos são marcados com %s (um texto), %d (um número inteiro) ou %.1f (um decimal com 1 casa), e o método formatted(…) preenche na ordem. Essas marcações são as mesmas do printf, que tem aula própria em Formatar Texto.

Exemplo: JSON

JSON é um formato de texto muito usado para trocar dados entre programas (por exemplo, entre um site e um servidor). Ele usa muitas aspas duplas, e é aí que o text block brilha: nenhuma barra.

public class Main {
    public static void main(String[] args) {
        String nome = "Ana";
        int idade = 30;
        double nota = 9.5;
        String json = """
                {
                  "nome": "%s",
                  "idade": %d,
                  "nota": %.1f
                }
                """.formatted(nome, idade, nota);
        System.out.print(json);
        String certo = """
                {"nome": "%s", "nota": %s}
                """.formatted(nome, nota);
        System.out.print(certo);
    }
}
$ java Main.java
{
  "nome": "Ana",
  "idade": 30,
  "nota": 9,5          « vírgula! JSON exige ponto
}
{"nome": "Ana", "nota": 9.5}
"""…""".formatted(nome, idade, nota)
O text block é uma String, então dá para chamar formatted direto no """ de fechamento. nome entra no %s, idade no %d e nota no %.1f.
9,5
Uma surpresa real: o computador da Ana está em português (pt_BR), e o %.1f segue o costume do país, com vírgula decimal. Para gente, ótimo; para JSON, errado.
"nota": %s
Com %s, o número vira texto do jeito do Java (o mesmo do println), sempre com ponto: 9.5. Outra saída é fixar o idioma, assunto de Formatar Texto.

Exemplo: HTML

HTML, a linguagem das páginas web, também é cheio de aspas e de recuos. Com text block, o código Java fica com a mesma cara da página:

public class Main {
    public static void main(String[] args) {
        String titulo = "Frutas da feira";
        String fruta1 = "maçã";
        String fruta2 = "banana";
        String html = """
                <html>
                  <body>
                    <h1>%s</h1>
                    <ul class="lista">
                      <li>%s</li>
                      <li>%s</li>
                    </ul>
                  </body>
                </html>
                """.formatted(titulo, fruta1, fruta2);
        System.out.print(html);
    }
}
$ java Main.java
<html>
  <body>
    <h1>Frutas da feira</h1>
    <ul class="lista">
      <li>maçã</li>
      <li>banana</li>
    </ul>
  </body>
</html>

Os recuos internos (2, 4, 6 espaços além da margem) foram preservados, e as aspas de class="lista" entraram sem barra nenhuma.


Text block ou String comum?

SituaçãoUse
Texto curto, uma linhaString comum: "Olá, Ana"
Texto de várias linhas (mensagens, menus, poemas)Text block
Texto com muitas aspas (JSON, HTML, SQL)Text block
Modelo a ser preenchidoText block + formatted()
Frase longa que deve sair numa linha sóText block com \ no fim das linhas, ou concatenação com +
Projeto em Java 8 ou 11Concatenação com \n (text blocks não existem lá)

Como o resultado é uma String comum, dá para usar todos os métodos nele:

public class Main {
    public static void main(String[] args) {
        String lista = """
                maçã
                banana
                uva
                """;
        System.out.println(lista.length());
        System.out.println(lista.lines().count());
        System.out.println(lista.contains("banana"));
    }
}
$ java Main.java
16       « 4 + 6 + 3 letras e 3 quebras de linha
3        « lines() separa o texto em linhas
true

Brinque com o código: mude a posição do """ de fechamento (mais para a esquerda, colado na última linha) e acrescente recuos em algumas linhas. Veja como a saída muda.

public class Main {
    public static void main(String[] args) {
        String menu = """
                1. Novo jogo
                2. Continuar
                  2.1 Último salvo
                3. Sair
                """;
        System.out.print(menu);
    }
}

Quando dá errado

error: illegal text block open delimiter sequence, missing line terminator

Este código tem um erro de propósito.

public class Main {
    public static void main(String[] args) {
        String texto = """Olá""";
        System.out.println(texto);
    }
}
$ javac Main.java
Main.java:3: error: illegal text block open delimiter sequence, missing line terminator
        String texto = """Olá""";
                          ^
Main.java:3: error: illegal text block open delimiter sequence, missing line terminator
        String texto = """Olá""";
                                ^
2 errors

O que aconteceu: depois do """ de abertura tem de vir uma quebra de linha ("sequência de abertura de text block ilegal, falta o fim de linha"). Text block não serve para texto de uma linha só, nem pode começar na mesma linha das aspas.

Como resolver: para uma linha, use aspas comuns: "Olá". Para várias, passe o texto para a linha de baixo do """.

error: unclosed text block

Este código tem um erro de propósito.

public class Main {
    public static void main(String[] args) {
        String texto = """
                Olá, mundo
                ;
        System.out.println(texto);
    }
}
$ javac Main.java
Main.java:3: error: unclosed text block
        String texto = """
                       ^
1 error

O que aconteceu: faltou o """ de fechamento ("text block não fechado"). O javac leu o resto do arquivo inteiro como texto e chegou ao fim sem achar as três aspas. O ^ aponta onde o bloco abriu.

Como resolver: feche com """;.

Apareceu uma linha em branco a mais

O que aconteceu: o text block terminava com quebra de linha (o """ estava na linha de baixo) e foi impresso com println, que acrescenta outra.

Como resolver: use print, ou cole o """ no fim da última linha.

O texto saiu todo recuado para a direita

O que aconteceu: o """ de fechamento ficou mais à esquerda que o texto, e a margem foi calculada a partir dele.

Como resolver: alinhe o """ de fechamento com a primeira coluna do texto.

Número com vírgula no JSON

O que aconteceu: %f/%.1f no formatted seguem o idioma do sistema; em pt_BR, a vírgula.

Como resolver: use %s para o número, ou formate com um idioma fixo (veja Formatar Texto).


Referência

EscritaEfeito
""" + quebra de linhaAbre o bloco (o texto começa na linha seguinte)
""" sozinho na última linhaFecha; o texto termina com \n; a posição dele entra no cálculo da margem
texto"""Fecha sem \n no fim
\ no fim da linhaJunta com a linha de baixo (sem quebra)
\sUm espaço que não é removido
\"""Três aspas dentro do texto
"""…""".formatted(a, b)Preenche os %s, %d… do modelo
texto.lines()As linhas do texto, uma a uma
texto.stripIndent()Aplica a mesma regra de margem a uma String qualquer

Exercícios

Missão final: monte o JSON de um pedido com um text block e formatted, usando as variáveis. A saída deve ter quatro linhas: {, depois "produto": "Café", e "quantidade": 2 (as duas com 2 espaços de recuo) e por fim }.

public class Main {
    public static void main(String[] args) {
        String produto = "Café";
        int quantidade = 2;
        // crie o text block e mostre com System.out.print
    }
}
public class Main {
    public static void main(String[] args) {
        String produto = "Café";
        int quantidade = 2;
        String pedido = """
                {
                  "produto": "%s",
                  "quantidade": %d
                }
                """.formatted(produto, quantidade);
        System.out.print(pedido);
    }
}

1. Abrir o bloco

Quantas aspas duplas abrem um text block?

2. Um espaço que fica

Qual escape mantém um espaço no fim de uma linha do text block?

3. O que define a margem (os espaços que são removidos) de um text block?

4. O text block abaixo termina com quebra de linha?

String s = """
        oi
        tchau""";

5. Um text block com a linha Ana e o """ de fechamento na linha de baixo é comparado com equals à String "Ana\n". O resultado é…


Resumo

  • Text block: """, quebra de linha, o texto, """. Existe desde o Java 15 e resulta numa String comum.
  • A margem é a linha mais à esquerda (incluindo o """ de fechamento); o que passa dela vira recuo no texto.
  • """ na linha de baixo = termina com \n; colado na última linha = sem \n.
  • Espaços no fim das linhas são removidos; \s mantém um. \ no fim da linha junta com a próxima.
  • Aspas não precisam de barra; só \""".
  • formatted() transforma o text block num modelo; cuidado com %f e a vírgula do pt_BR.