Du vill skriva ut en rad med produktnamn, antal och pris, men kolumnerna hamnar snett eller decimalerna ser fel ut. Med printf i Java kan du styra formatet direkt i utskriften, men resultatet beror också på datatyp och språkinställning.
Formatsträngen styr hur varje värde visas
- %s passar text, %d heltal och %f decimaltal.
- %.2f visar två decimaler, medan en bredd som %8.2f reserverar plats för minst åtta tecken.
- %n gör en radbrytning som passar plattformen.
- String.format() bygger en formaterad sträng; System.out.printf() skriver den direkt till konsolen.
- Ange en Locale uttryckligen när formatet måste vara konsekvent mellan datorer.
En formatsträng kopplar platshållare till argument
Tänk på formatsträngen som en liten mall: vanlig text står kvar, medan varje formatkod ersätts av ett argument. I Java kan du till exempel skriva System.out.printf("Namn: %s, antal: %d%n", "Kaffe", 3); för att få ut en rad med text och ett heltal.
De vanligaste koderna är %s för text, %d för heltal och %f för decimaltal. Ett format som %.2f begränsar decimalvisningen till två siffror, vilket passar en enkel utskrift av ett pris eller mätvärde.
Ordningen spelar roll. Första platshållaren använder det första argumentet, nästa använder det andra, och om typerna inte passar ihop kan formatteringen ge ett undantag i stället för den text du väntade dig. Jag tycker att det är lättast att felsöka när varje formatkod står nära den variabel den ska beskriva.
Bredd och precision löser olika problem
Två tal kan visa lika många decimaler men ändå hamna på olika positioner i en rapport. Då hjälper bredden: i %8.2f betyder 8 att fältet minst ska ta åtta tecken, medan .2 anger två decimaler.
Bredden är ett minimimått, inte ett tak. Om värdet kräver fler tecken får det fortfarande plats, så använd inte fältbredd som en metod för att kapa text eller siffror. För text kan precisionen däremot begränsa antalet tecken, exempelvis %.5s för högst fem tecken ur en sträng.
System.out.printf("%-12s %8.2f%n", "Kaffe", 42.5);
Flaggan - vänsterjusterar värdet; utan den fylls fältet normalt ut från vänster. Den skillnaden märks direkt när du skriver ut en tabell med namn och belopp på flera rader.
Locale avgör om decimaltecknet blir punkt eller komma
Ett test kan se rätt ut på din dator och ändå ge en oväntad rapport hos någon annan. Formateringen påverkas av lokalinställningar, så ett decimaltal kan visas med olika decimaltecken beroende på vilken Locale som används.
Om presentationen ska följa en bestämd lokal kan du skicka in den uttryckligen, till exempel System.out.printf(Locale.forLanguageTag("sv-SE"), "%.2f%n", 1234.5);. För maskinläsbara utdata, där ett fast format är viktigare än lokal typografi, är det bättre att välja en stabil locale som Locale.ROOT.
Java-dokumentationen för Formatter beskriver hur bredd, precision, argument och lokalanpassning samverkar. Det innebär att samma formatmall kan vara bra för en svensk konsolrapport men olämplig som direkt indata till ett annat program.
Välj printf eller String.format efter vad koden ska göra
Om målet är att visa information direkt i konsolen är System.out.printf() ett rakt val. Behöver du i stället spara resultatet, skicka det vidare eller bygga en sträng för ett gränssnitt, passar String.format() bättre.
| Behov | Val | Varför |
|---|---|---|
| Skriv en formaterad rad i konsolen | System.out.printf() |
Formaterar och skriver ut direkt. |
| Skapa en sträng att använda senare | String.format() |
Returnerar resultatet som en sträng. |
| Behåll en tydlig radbrytning i konsolen | %n |
Använder plattformens radseparator. |
| Skriv ut ett procenttecken | %% |
Visar ett bokstavligt procenttecken utan argument. |
Metoderna använder samma formatteringsregler, men skiljer sig åt i vad de gör med resultatet. Oracles Java-tutorial om printf och format visar också att printf och format finns som likvärdiga utskriftsmetoder i PrintStream.
De vanligaste felen går att spåra till formatkoden
När en formattering kraschar är felmeddelandet ofta mer specifikt än den synliga utskriften. Oracles API-dokumentation listar bland annat undantag för formatkod som inte passar argumentets typ, ogiltig precision och okända konverteringar.
| Situation | Trolig orsak | Gör så här |
|---|---|---|
Undantag vid exempelvis %d |
Argumentet är inte ett heltal av en kompatibel typ. | Kontrollera typen och välj rätt konvertering, till exempel %s för text. |
| Decimaltalet får oväntat antal siffror | Precision saknas eller är fel angiven. | Använd exempelvis %.2f när två visade decimaler önskas. |
| Procenttecknet ger fel eller kräver argument | Ett ensamt % tolkas som början på en formatkod. |
Skriv %% för att visa tecknet bokstavligt. |
| En extra tom rad eller fel radbrytning visas | %n har kombinerats med en extra radbrytning i texten. |
Välj en enda radbrytning, helst %n i formaterade utskrifter. |
En liten men användbar detalj är att %n inte förbrukar något argument, och det gör inte heller %%. Om antalet argument verkar rätt men fel ändå uppstår, kontrollera därför först om en faktisk formatkod har fått fel typ eller fel precision.
Gör formatet förutsägbart innan du skickar utdata vidare
För en konsolrad räcker det ofta att välja rätt konvertering och lägga till en radbrytning. När texten däremot ska jämföras i tester, sparas i filer eller läsas av en annan tjänst behöver du även bestämma lokalinställning och exakt antal decimaler.
En enkel tumregel är: format för människor med en uttrycklig Locale, och håll maskinläsbar utdata konsekvent från början till slut. Då slipper du att en snygg konsolrad senare blir en svårtolkad datarad.