1. Información general
En este tutorial, veremos diferentes enfoques para el formato de números en Java y cómo implementarlos.
2. Formato de número básico con formato de cadena #
El método de formato String # es muy útil para formatear números. El método toma dos argumentos. El primer argumento describe el patrón de cuántos lugares decimales queremos ver, y el segundo argumento es el valor dado:
double value = 4.2352989244d; assertThat(String.format("%.2f", value)).isEqualTo("4.24"); assertThat(String.format("%.3f", value)).isEqualTo("4.235");
3. Formato decimal por redondeo
En Java, tenemos dos tipos primitivos que representan números decimales : flotante y decimal :
double myDouble = 7.8723d; float myFloat = 7.8723f;
El número de posiciones decimales puede ser diferente según las operaciones que se realicen. En la mayoría de los casos, solo nos interesan los primeros dos decimales. Echemos un vistazo a algunas formas de formatear un decimal redondeando.
3.1. Usar BigDecimal para formatear números
La clase BigDecimal proporciona métodos para redondear a un número específico de decimales. Creemos un método auxiliar que devolverá un doble, redondeado al número deseado de lugares:
public static double withBigDecimal(double value, int places) { BigDecimal bigDecimal = new BigDecimal(value); bigDecimal = bigDecimal.setScale(places, RoundingMode.HALF_UP); return bigDecimal.doubleValue(); }
Comenzamos con una nueva instancia de BigDecimal con nuestro valor decimal original. Luego, al establecer la escala, proporcionamos el número de lugares decimales que queremos y cómo queremos redondear nuestro número . El uso de este método nos permite formatear fácilmente un valor doble :
double D = 4.2352989244d; assertThat(withBigDecimal(D, 2)).isEqualTo(4.24); assertThat(withBigDecimal(D, 3)).isEqualTo(4.235);
3.2. Usando Math # round
También podemos aprovechar los métodos estáticos de la clase Math para redondear un valor doble a un decimal específico. En este caso, podemos ajustar el número de lugares decimales multiplicando y luego dividiendo por 10 ^ n . Revisemos nuestro método de ayuda:
public static double withMathRound(double value, int places) { double scale = Math.pow(10, places); return Math.round(value * scale) / scale; }
assertThat(withMathRound(D, 2)).isEqualTo(4.24); assertThat(withMathRound(D, 3)).isEqualTo(4.235);
Sin embargo, esta forma solo se recomienda en casos particulares, ya que a veces la salida puede redondearse de manera diferente a como se esperaba antes de imprimirla.
Esto se debe a que Math # round está truncando el valor . Veamos cómo puede suceder esto:
System.out.println(withMathRound(1000.0d, 17)); // Gives: 92.23372036854776 !! System.out.println(withMathRound(260.775d, 2)); // Gives: 260.77 instead of expected 260.78
Por tanto, el método solo se incluye con fines de aprendizaje.
4. Dar formato a diferentes tipos de números
En algunos casos particulares, es posible que queramos formatear un número para un tipo específico como moneda, entero grande o porcentaje.
4.1. Formateo de números enteros grandes con comas
Siempre que tengamos un entero grande en nuestra aplicación, es posible que queramos mostrarlo con comas, usando DecimalFormat con un patrón predefinido:
public static String withLargeIntegers(double value) { DecimalFormat df = new DecimalFormat("###,###,###"); return df.format(value); } int value = 123456789; assertThat(withLargeIntegers(value)).isEqualTo("123,456,789");
4.2. Relleno de un número
En algunos casos, es posible que deseemos rellenar un número con ceros para una longitud específica. Aquí, podemos usar el método de formato String # , como se describió anteriormente:
public static String byPaddingZeros(int value, int paddingLength) { return String.format("%0" + paddingLength + "d", value); } int value = 1; assertThat(byPaddingOutZeros(value, 3)).isEqualTo("001");
4.3. Formateo de números con dos ceros después del decimal
Para poder imprimir cualquier número dado con dos ceros después del punto decimal, usaremos una vez más la clase DecimalFormat con un patrón predefinido:
public static double withTwoDecimalPlaces(double value) { DecimalFormat df = new DecimalFormat("#.00"); return new Double(df.format(value)); } int value = 12; assertThat(withTwoDecimalPlaces(value)).isEqualTo(12.00);
En este caso, hemos creado un nuevo formato con un patrón que especifica dos ceros después del punto decimal .
4.4. Formato y porcentajes
Es posible que de vez en cuando necesitemos mostrar porcentajes.
En este caso, podemos usar el método NumberFormat # getPercentInstance . Este método nos permite proporcionar una configuración regional para imprimir el valor en un formato que sea correcto para el país que especificó:
public static String forPercentages(double value, Locale locale) { NumberFormat nf = NumberFormat.getPercentInstance(locale); return nf.format(value); } double value = 25f / 100f; assertThat(forPercentages(value, new Locale("en", "US"))).isEqualTo("25%");
4.5. Formato de número de moneda
Una forma común de almacenar divisas en nuestra aplicación es mediante BigDecimal . ¿Qué pasa si queremos mostrárselos al usuario? En este caso, podemos usar la clase NumberFormat :
public static String currencyWithChosenLocalisation(double value, Locale locale) { NumberFormat nf = NumberFormat.getCurrencyInstance(locale); return nf.format(value); }
Obtenemos la instancia de moneda para una configuración regional determinada y luego simplemente llamamos al método de formato con el valor. El resultado es el número que se muestra como moneda para el país especificado:
double value = 23_500; assertThat(currencyWithChosenLocalisation(value, new Locale("en", "US"))).isEqualTo("$23,500.00"); assertThat(currencyWithChosenLocalisation(value, new Locale("zh", "CN"))).isEqualTo("¥23,500.00"); assertThat(currencyWithChosenLocalisation(value, new Locale("pl", "PL"))).isEqualTo("23 500 zł");
5. Casos de uso de formato avanzado
DecimalFormat es una de las formas más populares de formatear un número decimal en Java. Al igual que en los ejemplos anteriores, escribiremos un método auxiliar:
public static double withDecimalFormatLocal(double value) { DecimalFormat df = (DecimalFormat) NumberFormat.getNumberInstance(Locale.getDefault()); return new Double(df.format(value)); }
Nuestro tipo de formato obtendrá la configuración predeterminada para una localización determinada.
El formato decimal se maneja de manera diferente en diferentes países utilizando sus sistemas numéricos. Por ejemplo, el carácter de agrupación (coma en EE. UU., Pero espacio o punto en otras configuraciones regionales), el tamaño de agrupación (tres en EE. UU. Y la mayoría de las configuraciones regionales, pero diferente en India) o el carácter decimal (punto en EE. UU., Pero una coma en otras configuraciones regionales).
double D = 4.2352989244d; assertThat(withDecimalFormatLocal(D)).isEqualTo(4.235);
También podemos ampliar esta funcionalidad para proporcionar algunos patrones específicos:
public static double withDecimalFormatPattern(double value, int places) { DecimalFormat df2 = new DecimalFormat("#,###,###,##0.00"); DecimalFormat df3 = new DecimalFormat("#,###,###,##0.000"); if (places == 2) return new Double(df2.format(value)); else if (places == 3) return new Double(df3.format(value)); else throw new IllegalArgumentException(); } assertThat(withDecimalFormatPattern(D, 2)).isEqualTo(4.24); assertThat(withDecimalFormatPattern(D, 3)).isEqualTo(4.235);
Aquí permitimos a nuestro usuario configurar DecimalFormat mediante el patrón elegido en función del número de espacios.
6. Conclusión
En este artículo, analizamos brevemente diferentes formas de formatear números en Java. Como podemos ver, no existe una mejor manera de hacer esto. Se pueden seguir muchos enfoques, ya que cada uno de ellos tiene sus propias características.
Como siempre, el código para estos ejemplos está disponible en GitHub.