1. Información general
En este artículo, discutiremos el formato de cadenas en Java utilizando la clase java.util.Formatter , que brinda soporte para la justificación y alineación del diseño.
2. Cómo utilizar el formateador
¿Recuerdas el printf de C ? Formatear una cadena en Java se siente muy similar.
El método format () del formateador se expone a través de un método estático de la clase String . Este método acepta una cadena de plantilla y una lista de argumentos para completar la plantilla con:
String greetings = String.format( "Hello Folks, welcome to %s !", "Baeldung");
La cadena resultante es:
"Hello Folks, welcome to Baeldung !"
Una plantilla es una cadena que contiene texto estático y uno o más especificadores de formato, que indican qué argumento se colocará en la posición particular.
En este caso, hay un único especificador de formato % s , que se reemplaza por el argumento correspondiente.
3. Especificadores de formato
3.1. Sintaxis general
La sintaxis de los especificadores de formato para el tipo General, Carácter y Numérico es:
%[argument_index$][flags][width][.precision]conversion
Los especificadores argument_index, flag, width y precision son opcionales.
- La parte argumento_index es un entero i , lo que indica que el i-ésimo argumento de la lista de argumentos debe usarse aquí
- banderas es un conjunto de caracteres que se utilizan para modificar el formato de salida
- el ancho es un número entero positivo que indica el número mínimo de caracteres que se escribirán en la salida
- La precisión es un número entero que generalmente se usa para restringir el número de caracteres, cuyo comportamiento específico depende de la conversión
- es la parte obligatoria. Es un carácter que indica cómo se debe formatear el argumento. El conjunto de conversiones válidas para un argumento dado depende del tipo de datos del argumento
En nuestro ejemplo anterior, si queremos especificar el número de un argumento explícitamente, podemos escribirlo usando índices de argumento de 1 $ y 2 $ .
Ambos son el primer y segundo argumento respectivamente:
String greetings = String.format( "Hello %2$s, welcome to %1$s !", "Baeldung", "Folks");
3.2. Para la fecha / hora Representación
%[argument_index$][flags][width]conversion
Nuevamente, el argumento_index, las banderas y el ancho son opcionales.
Tomemos un ejemplo para entender esto:
@Test public void whenFormatSpecifierForCalendar_thenGotExpected() { Calendar c = new GregorianCalendar(2017, 11, 10); String s = String.format( "The date is: %tm %1$te,%1$tY", c); assertEquals("The date is: 12 10,2017", s); }
Aquí, para cada especificador de formato, se usará el primer argumento, por lo tanto, 1 $ . Aquí, si omitimos el argumento_index para el segundo y tercer especificador de formato, intenta encontrar 3 argumentos, pero debemos usar el mismo argumento para los 3 especificadores de formato.
Entonces, está bien si no especificamos el argumento _index para el primero, pero necesitamos especificarlo para los otros dos.
La bandera aquí está formada por dos caracteres. Donde el primer carácter es siempre una 't' o una 'T' . El segundo carácter depende de qué parte del Calendario se mostrará.
En nuestro ejemplo, los primeros especificadores de formato tm , indican el mes con formato de dos dígitos, te indica el día del mes y tY indica el año con el formato de cuatro dígitos.
3.3. Especificadores de formato sin argumentos
%[flags][width]conversion
Las banderas opcionales y el ancho son los mismos que se definen en las secciones anteriores.
La conversión requerida es un carácter o una Cadena que indica el contenido que se insertará en la salida. Actualmente, solo el '%' y la nueva línea 'n' se pueden imprimir usando esto:
@Test public void whenNoArguments_thenExpected() { String s = String.format("John scored 90%% in Fall semester"); assertEquals("John scored 90% in Fall semester", s); }
Dentro de format () , si queremos imprimir '%' , necesitamos escapar usando '%%' .
4. Conversiones
Ahora profundicemos en cada detalle de la sintaxis del Especificador de formato, comenzando con una conversión . Tenga en cuenta que puede encontrar todos los detalles en los javadocs del formateador .
Como notamos en los ejemplos anteriores, la parte de conversión es necesaria en todos los especificadores de formato y se puede dividir en varias categorías.
Echemos un vistazo a cada uno tomando ejemplos.
4.1. General
Se utiliza para cualquier tipo de argumento. Las conversiones generales son:
- 'b' o 'B' - para valores booleanos
- 'h' o 'H' - para HashCode
- 's' o 'S' - para String , si es nulo , imprime "nulo", de lo contrario arg.toString ()
Ahora intentaremos mostrar valores booleanos y de cadena , utilizando las conversiones correspondientes:
@Test public void givenString_whenGeneralConversion_thenConvertedString() { String s = String.format("The correct answer is %s", false); assertEquals("The correct answer is false", s); s = String.format("The correct answer is %b", null); assertEquals("The correct answer is false", s); s = String.format("The correct answer is %B", true); assertEquals("The correct answer is TRUE", s); }
4.2. Personaje
Used for the basic types which represent Unicode characters: char, Character, byte, Byte, short, and Short. This conversion can also be used for the types int and Integer when the Character.isValidCodePoint(int) returns true for them.
It can be written as ‘c’ or ’C’ based on the case we want.
Let's try to print some characters:
@Test public void givenString_whenCharConversion_thenConvertedString() { String s = String.format("The correct answer is %c", 'a'); assertEquals("The correct answer is a", s); s = String.format("The correct answer is %c", null); assertEquals("The correct answer is null", s); s = String.format("The correct answer is %C", 'b'); assertEquals("The correct answer is B", s); s = String.format("The valid unicode character: %c", 0x0400); assertTrue(Character.isValidCodePoint(0x0400)); assertEquals("The valid unicode character: Ѐ", s); }
Let's take one more example of an invalid code point:
@Test(expected = IllegalFormatCodePointException.class) public void whenIllegalCodePointForConversion_thenError() { String s = String.format("The valid unicode character: %c", 0x11FFFF); assertFalse(Character.isValidCodePoint(0x11FFFF)); assertEquals("The valid unicode character: Ā", s); }
4.3. Numeric – Integral
These are used for Java integral types: byte, Byte, short, Short, int and Integer, long, Long, and BigInteger. There are three conversions in this category:
- ‘d' – for decimal number
- ‘o' – for octal number
- ‘X' or ‘x' – for hexadecimal number
Let's try to print each of these:
@Test public void whenNumericIntegralConversion_thenConvertedString() { String s = String.format("The number 25 in decimal = %d", 25); assertEquals("The number 25 in decimal = 25", s); s = String.format("The number 25 in octal = %o", 25); assertEquals("The number 25 in octal = 31", s); s = String.format("The number 25 in hexadecimal = %x", 25); assertEquals("The number 25 in hexadecimal = 19", s); }
4.4. Numeric – Floating Point
Used for Java floating-point types: float, Float, double, Double, and BigDecimal
- ‘e' or ‘E' – formatted as a decimal number in computerized scientific notation
- ‘f' – formatted as a decimal number
- ‘g' or ‘G' – based on the precision value after rounding, this conversion formats into computerized scientific notation or decimal format
Let's try to print the floating point numbers:
@Test public void whenNumericFloatingConversion_thenConvertedString() { String s = String.format( "The computerized scientific format of 10000.00 " + "= %e", 10000.00); assertEquals( "The computerized scientific format of 10000.00 = 1.000000e+04", s); String s2 = String.format("The decimal format of 10.019 = %f", 10.019); assertEquals("The decimal format of 10.019 = 10.019000", s2); }
4.5. Other Conversions
- Date/Time – for Java types which are capable of encoding a date or time: long, Long, Calendar, Date and TemporalAccessor. For this, we need to use prefixed ‘t' or ‘T', as we saw earlier
- Percent – prints a literal ‘%' (‘\u0025')
- Line Separator – prints a platform-specific line separator
Let's have a look at a simple example:
@Test public void whenLineSeparatorConversion_thenConvertedString() { String s = String.format("First Line %nSecond Line"); assertEquals("First Line \n" + "Second Line", s); }
5. Flags
Flags, in general, are used to format the output. Whereas in case of date and time, they are used to specify which part of the date is to be displayed, as we saw in the Section 4 example.
A number of flags are available, a list of which can be found in the documentation.
Let’s see a flag example to understand it’s usage. ‘-‘ is used to format the output as left justified:
@Test public void whenSpecifyFlag_thenGotFormattedString() { String s = String.format("Without left justified flag: %5d", 25); assertEquals("Without left justified flag: 25", s); s = String.format("With left justified flag: %-5d", 25); assertEquals("With left justified flag: 25 ", s); }
6. Precision
For general conversions, precision is just the maximum number of characters to be written to the output. Whereas, f or the floating-point conversions the precision is the number of digits after the radix point.
The first statement is an example of precision with floating-point numbers, and the second one with general conversions:
@Test public void whenSpecifyPrecision_thenGotExpected() { String s = String.format( "Output of 25.09878 with Precision 2: %.2f", 25.09878); assertEquals("Output of 25.09878 with Precision 2: 25.10", s); String s2 = String.format( "Output of general conversion type with Precision 2: %.2b", true); assertEquals("Output of general conversion type with Precision 2: tr", s2); }
7. Argument Index
As mentioned previously, theargument_index is an integer that indicates the position of the argument in the argument list. 1$ indicates the first argument, 2$ the second argument, and so on.
Also, there is another way to reference arguments by position, by using the ‘<‘ (‘\u003c') flag, which means the argument from the previous format specifier will be re-used. For example, these two statements would produce the identical output:
@Test public void whenSpecifyArgumentIndex_thenGotExpected() { Calendar c = Calendar.getInstance(); String s = String.format("The date is: %tm %1$te,%1$tY", c); assertEquals("The date is: 12 10,2017", s); s = String.format("The date is: %tm %
8. Other Ways of Using Formatter
Till now we saw the use of format() method of the Formatter class. We can also create a Formatter instance, and use that to invoke the format() method.
We can create an instance by passing in an Appendable, OutputStream, File or file name. Based on this, the formatted String is stored in an Appendable, OutputStream, File respectively.
Let's see an example of using it with an Appendable. We can use it with others in the same way.
8.1. Using Formatter With Appendable
Let's create a StringBuilder instance sb, and create a Formatter using it. Then we'll invoke format() to format a String:
@Test public void whenCreateFormatter_thenFormatterWithAppendable() { StringBuilder sb = new StringBuilder(); Formatter formatter = new Formatter(sb); formatter.format("I am writting to a %s Instance.", sb.getClass()); assertEquals( "I am writting to a class java.lang.StringBuilder Instance.", sb.toString()); }
9. Conclusion
In this article, we saw the formatting facilities provided by the java.util.Formatter class. We saw various syntax that can be used to format the String and the conversion types that can be used for different data types.
As usual, the code for the examples we saw can be found over on Github.