Przejdź do treści

Formatowanie i składanie tekstu

  • Teksty i String
  • poziom: początkujący
  • aktualizacja: 16 sierpnia 2026

Łączenie kilku napisów operatorem + jest czytelne, ale w pętli tworzy stos obiektów pośrednich, z których każdy od razu ląduje na śmietniku. Do raportów i tabel lepiej pasuje StringBuilder, a układ kolumn najłatwiej kontrolować przez String.format. Od Javy 15 wielowierszowy HTML albo SQL zapiszesz jako blok tekstu """ — bez ręcznego dopisywania \n i bez poprzedzania każdego cudzysłowu ukośnikiem.

JAVA FormatowanieTekstu.java 112 linii Pobierz .java
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Locale;

/**
 * String.format, StringBuilder i bloki tekstu — skryptyJAVA.pl
 * Zapisz jako: FormatowanieTekstu.java
 */
public final class FormatowanieTekstu {

    private static final Locale POLSKI = Locale.forLanguageTag("pl-PL");

    /** Prosty, niezmienny wiersz danych do raportu. */
    public record Produkt(String nazwa, int ilosc, BigDecimal cena) {}

    private FormatowanieTekstu() {
        // Klasa narzędziowa nie wymaga obiektów.
    }

    /** Formatuje liczby zgodnie z polskim locale: grupowanie tysięcy i przecinek dziesiętny. */
    public static String etykieta(Produkt produkt) {
        return String.format(POLSKI, "%s — %,d szt. po %,.2f zł",
                produkt.nazwa(), produkt.ilosc(), produkt.cena());
    }

    /** Buduje tabelę bez tworzenia nowego pełnego napisu przy każdym obrocie pętli. */
    public static String tabela(List<Produkt> produkty) {
        StringBuilder wynik = new StringBuilder();
        wynik.append(String.format(POLSKI, "%-22s %8s %13s%n", "Produkt", "Ilość", "Wartość"));
        wynik.append("-".repeat(45)).append(System.lineSeparator());

        BigDecimal suma = BigDecimal.ZERO;
        for (Produkt produkt : produkty) {
            // Zaokrąglamy przed dodaniem, żeby stopka zgadzała się z sumą wydrukowanych wierszy.
            BigDecimal wartosc = produkt.cena()
                    .multiply(BigDecimal.valueOf(produkt.ilosc()))
                    .setScale(2, RoundingMode.HALF_UP);
            suma = suma.add(wartosc);
            wynik.append(String.format(POLSKI, "%-22s %8d %10.2f zł%n",
                    skroc(produkt.nazwa(), 22), produkt.ilosc(), wartosc));
        }

        wynik.append("-".repeat(45)).append(System.lineSeparator());
        wynik.append(String.format(POLSKI, "%-31s %10.2f zł%n", "Razem:", suma));
        return wynik.toString();
    }

    /**
     * Skraca tekst do zadanej liczby znaków i dopisuje wielokropek, zamiast uciąć po cichu.
     * Liczy punkty kodowe: nie rozrywa par zastępczych, ale może przeciąć flagę lub emoji ZWJ.
     */
    public static String skroc(String tekst, int limit) {
        if (limit < 1) {
            return "";
        }
        if (tekst.codePointCount(0, tekst.length()) <= limit) {
            return tekst;
        }
        return tekst.substring(0, tekst.offsetByCodePoints(0, limit - 1)) + "…";
    }

    /**
     * Wstawia dane do czytelnego bloku tekstu; treść jest wcześniej kodowana dla HTML-a.
     * Oba argumenty muszą być różne od null.
     */
    public static String stronaHtml(String tytul, String tresc) {
        String szablon = """
                <!doctype html>
                <html lang="pl">
                <head>
                    <meta charset="UTF-8">
                    <title>%s</title>
                </head>
                <body>
                    <h1>%s</h1>
                    <p>%s</p>
                </body>
                </html>
                """;

        String bezpiecznyTytul = kodujHtml(tytul);
        return szablon.formatted(bezpiecznyTytul, bezpiecznyTytul, kodujHtml(tresc));
    }

    /**
     * Minimalne kodowanie tekstu umieszczanego między znacznikami HTML.
     * Argument nie może być null — metoda nie sprawdza go i rzuci NullPointerException.
     */
    public static String kodujHtml(String tekst) {
        return tekst.replace("&", "&amp;")
                    .replace("<", "&lt;")
                    .replace(">", "&gt;")
                    .replace("\"", "&quot;")
                    .replace("'", "&#39;");
    }

    // ── PRZYKŁADY ───────────────────────────────────────────
    public static void main(String[] args) {
        List<Produkt> produkty = List.of(
                new Produkt("Kawa ziarnista", 2, new BigDecimal("39.90")),
                new Produkt("Kubek programisty", 12, new BigDecimal("24.50")),
                new Produkt("Zestaw kubków termicznych premium", 3, new BigDecimal("19.99")),
                new Produkt("Książka o Javie", 1_250, new BigDecimal("79.99")));

        System.out.println(etykieta(produkty.get(3)));
        System.out.println();
        System.out.print(tabela(produkty));
        System.out.println();
        System.out.println(stronaHtml("Java & tekst", "Bezpieczne <formatowanie>"));
    }
}

Jak użyć tego skryptu

  1. Zapisz kod jako FormatowanieTekstu.java (nazwa pliku musi zgadzać się z nazwą klasy publicznej) i uruchom przez java FormatowanieTekstu.java. Program wypisze polsko sformatowaną etykietę, tabelę produktów i gotowy dokument HTML.
  2. Do pojedynczego komunikatu użyj String.format(locale, wzorzec, argumenty) albo krótszego wzorzec.formatted(argumenty). Znaczniki %s, %d i %.2f oznaczają napis, liczbę całkowitą i liczbę z dwoma miejscami.
  3. Gdy składasz tekst w pętli, utwórz jeden StringBuilder, dopisuj fragmenty metodą append, a na końcu pobierz wynik przez toString(). Metoda tabela pokazuje pełny wzorzec — razem z skroc, bo sama precyzja we wzorcu (np. %-22.22s) ucina za długą nazwę bez śladu i może rozdzielić parę zastępczą. skroc chroni pojedyncze punkty kodowe, lecz nie całe klastry grafemowe, np. flagi i rodzinne emoji ZWJ.
  4. Wielowierszowy szablon umieść między """, a pola wstaw przez formatted. Jeśli dane pochodzą od użytkownika, zakoduj je odpowiednio dla miejsca docelowego — w przykładzie robi to kodujHtml.

Warto wiedzieć

  • Zawsze podawaj Locale, gdy wynik ma trafić do użytkownika albo do pliku o ustalonym formacie. Bez niego ten sam kod wypisze 1,234.50 na Twoim laptopie i 1 234,50 na serwerze produkcyjnym. I uważaj na to drugie: separatorem tysięcy w polskim locale jest twarda spacja U+00A0, a nie zwykła. Napisu „1 250 000” z %,d nie oczyścisz przez replace(" ", "") ani nie sparsujesz wprost z powrotem na liczbę. Do danych maszynowych — CSV, JSON, kolumna liczbowa w bazie — formatuj bez przecinka we wzorcu, czyli samym %d.
  • W formaterze %n oznacza separator linii właściwy dla systemu, natomiast \n zawsze pojedynczy znak LF. Do tekstu wyświetlanego w terminalu zwykle wybieraj %n lub System.lineSeparator().
  • StringBuilder nie jest bezpieczny wątkowo, ale lokalna zmienna w metodzie nie jest współdzielona i właśnie tak należy go zwykle używać. Nie zastępuj go wolniejszym StringBuffer bez konkretnej potrzeby synchronizacji.
  • Kodowanie HTML zależy od kontekstu. Metoda z przykładu nadaje się do zwykłego tekstu między znacznikami, lecz nie zastępuje kodowania adresów URL, JavaScriptu ani wartości CSS. Do rozbudowanych stron użyj silnika szablonów z automatycznym escapingiem.
#formatowanie #locale #record #blok tekstu #html

Podobne skrypty