Skip to content

Yet another programming solutions log

Sample bits from programming for the future generations.

Technologies Technologies
  • Algorithms and Data Structures
  • Java Tutorials
  • JUnit Tutorial
  • MongoDB Tutorial
  • Quartz Scheduler Tutorial
  • Spock Framework Tutorial
  • Spring Framework
  • Bash Tutorial
  • Clojure Tutorial
  • Design Patterns
  • Developer’s Tools
  • Productivity
  • About
Expand Search Form

Java Formattable example

farenda 2015-09-01 0

Problem:

How to print Java object using custom format? Since Java 5 there’s Formattable interface exactly for that purpose. Here’s an example of how to use it.

Solution:

Java has very flexible formatting syntax and allows to output text in very different ways. Since Java 5 there’s a java.util.Formattable interface that allows to apply custom formatting for printing own objects, which is very cool. :-) The interface has only one method formatTo(…) that should be implemented.

In the following example we create two books and print them applying different formatting rules: justification, alternate format, locales, applying size constraints:

package com.farenda.java.util;

import java.util.Formattable;
import java.util.Formatter;
import java.util.List;
import java.util.Locale;

import static java.util.Arrays.asList;
import static java.util.FormattableFlags.*;

public class FormattableExample {

    public static class Book implements Formattable {

        private String symbol;
        private String bookName;
        private String polishName;

        public Book(String symbol, String bookName, String polishName) {
            this.symbol = symbol;
            this.bookName = bookName;
            this.polishName = polishName;
        }

        @Override
        public void formatTo(Formatter fmt, int flags, int width, int precision) {
            StringBuilder sb = new StringBuilder();

            String name = computeName(fmt, flags, precision);
            applyPrecision(precision, sb, name);
            applyFilling(flags, width, sb);

            fmt.format(sb.toString());
        }

        private void applyFilling(int flags, int minWidth, StringBuilder sb) {
            int currentLength = sb.length();
            if (currentLength < minWidth) {
                // prepend or append spaces depending on justification
                boolean leftJustified = isEnabled(flags, LEFT_JUSTIFY);
                for (int i = 0, toAdd = minWidth - currentLength; i < toAdd; i++) {
                    if (leftJustified) {
                        sb.append(' ');
                    } else {
                        sb.insert(0, ' ');
                    }
                }
            }
        }

        private void applyPrecision(int precision, StringBuilder sb, String out) {
            if (unspecified(precision) || fitsInPrecision(precision, out)) {
                sb.append(out);
            } else {
                sb.append(out.substring(0, precision-1)).append('*');
            }
        }

        private boolean fitsInPrecision(int precision, String out) {
            return out.length() < precision;
        }

        private boolean unspecified(int precision) {
            return precision == -1;
        }

        private String computeName(Formatter fmt, int flags, int precision) {
            return shouldUseSymbol(flags, precision) ? symbol : getLocalizedName(fmt);
        }

        private String getLocalizedName(Formatter fmt) {
            return fmt.locale().equals(Locale.forLanguageTag("pl_PL"))
                    ? polishName : bookName;
        }

        private boolean shouldUseSymbol(int flags, int precision) {
            return isEnabled(flags, ALTERNATE) || (precision != -1 && precision < 10);
        }

        private boolean isEnabled(int flags, int leftJustify) {
            return (flags & leftJustify) == leftJustify;
        }

        @Override
        public String toString() {
            return String.format("[%s] %s", symbol, bookName);
        }
    }

    public static void main(String[] args) {
        List<Book> books = asList(
                new Book("GOF",
                        "Design Patterns: Elements of Reusable Object-Oriented Software",
                        "Wzorce projektowe. Elementy oprogramowania obiektowego wielokrotnego użytku"),
                new Book("Wizard Book",
                        "Structure and Interpretation of Computer Programs",
                        "Struktura i interpretacja programów komputerowych"));

        for (Book book : books) {
            printBook(book);
        }
    }

    private static void printBook(Book book) {
        System.out.println("Format: formatted output");
        System.out.printf("\"%%s\"(toString()): '%s'%n", book.toString());
        System.out.printf("\"%%s\": '%s'%n", book);
        // Alternate format:
        System.out.printf("\"%%#s\"(alternate): '%#s'%n", book);
        System.out.printf("\"%%-10.5s\"(left,width,precision): '%-10.5s'%n", book);
        System.out.printf("\"%%.13s\": '%.13s'%n", book);
        // With custom Locale:
        System.out.printf(Locale.forLanguageTag("pl_PL"),
                         "\"%%25s\"(pl_PL): '%25s'%n", book);
        System.out.println();
    }
}

And here’s the output of the program:

Format: formatted output
"%s"(toString()): '[GOF] Design Patterns: Elements of Reusable Object-Oriented Software'
"%s": 'Design Patterns: Elements of Reusable Object-Oriented Software'
"%#s"(alternate): 'GOF'
"%-10.5s"(left,width,precision): 'GOF       '
"%.13s": 'Design Patte*'
"%25s"(pl_PL): 'Wzorce projektowe. Elementy oprogramowania obiektowego wielokrotnego użytku'

Format: formatted output
"%s"(toString()): '[Wizard Book] Structure and Interpretation of Computer Programs'
"%s": 'Structure and Interpretation of Computer Programs'
"%#s"(alternate): 'Wizard Book'
"%-10.5s"(left,width,precision): 'Wiza*     '
"%.13s": 'Structure an*'
"%25s"(pl_PL): 'Struktura i interpretacja programów komputerowych'

The output is pretty clear. One thing to note is how precision and width work together. This can be seen in the second book %-10.5s format. Even though width is 10 characters, the output contains only 5 (precision size) of them from the book, the rest is padding. So the way to interpret that is: width is the size of the output and precision is the part of output designated to use.

Share with the World!
Categories Java Tags java, java-util
Previous: Bash script parameters
Next: Spring properties file

Recent Posts

  • Java 8 Date Time concepts
  • Maven dependency to local JAR
  • Caesar cipher in Java
  • Java casting trick
  • Java 8 flatMap practical example
  • Linked List – remove element
  • Linked List – insert element at position
  • Linked List add element at the end
  • Create Java Streams
  • Floyd Cycle detection in Java

Pages

  • About Farenda
  • Algorithms and Data Structures
  • Bash Tutorial
  • Bean Validation Tutorial
  • Clojure Tutorial
  • Design Patterns
  • Java 8 Streams and Lambda Expressions Tutorial
  • Java Basics Tutorial
  • Java Collections Tutorial
  • Java Concurrency Tutorial
  • Java IO Tutorial
  • Java Tutorials
  • Java Util Tutorial
  • Java XML Tutorial
  • JUnit Tutorial
  • MongoDB Tutorial
  • Quartz Scheduler Tutorial
  • Software Developer’s Tools
  • Spock Framework Tutorial
  • Spring Framework

Tags

algorithms bash bean-validation books clojure design-patterns embedmongo exercises git gof gradle groovy hateoas hsqldb i18n java java-basics java-collections java-concurrency java-io java-lang java-time java-util java-xml java8 java8-files junit linux lists log4j logging maven mongodb performance quartz refactoring regex rest slf4j solid spring spring-boot spring-core sql unit-tests

Yet another programming solutions log © 2021

sponsored