10 abr 2014

Problemas con el separador de los números decimales (punto o coma) en Java

En ocasiones podemos tener problemas con el formato de los números decimales, ya que el carácter que separa la parte entera, de la parte decimal, puede ser un punto o una coma. Depende del idioma que tenga configurado por defecto el sistema operativo. Si tenemos configurado español y escribimos un número con decimales, escribirá la coma, pero si leemos un número escrito de esta forma e intentamos asignárselo a un float nos dará error porque está esperando un punto, que es el formato interno con el que trabaja el compilador.
Por ejemplo el siguiente código:
public void leerVectorDiscos() throws FileNotFoundException     {
        Scanner sc = new Scanner(new File("archivo.txt"));
        String fila;
        String[] vectSt;
        for (int j=0;j<hd.length;j++)
        {
            fila=sc.nextLine();
            vectSt=fila.split("\t");
            hd[j].setTecnologia(vectSt[0]); 
            hd[j].setCapacidad(Integer.parseInt(vectSt[1]));
            hd[j].setVelocidad(Float.parseFloat(vectSt[2]));
        }
        sc.close();
}
producirá esta excepción:
Exception in thread "main" java.lang.NumberFormatException: For input string: "9600,00"
            at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1241)
            at java.lang.Float.parseFloat(Float.java:452)
            at java500_1.VectorDiscos.leerVectorDiscos(VectorDiscos.java:118)
            at java500_1.Java500_1.main(Java500_1.java:36)
Java Result: 1

Una solución es utilizar la clase Numberformat, para especificar el formato que va a tener un número decimal:
float numf;
Locale spanish = new Locale(“es”, “ES”);
NumberFormat nf= NumberFormat.getInstance(spanish);
numf= nf.parse(st[2]).floatValue();

Hay que incluir los correspondientes import:
import java.text.NumberFormat;
import java.util.Locale;

De esta forma como estamos indicando que el idioma local es español, tomará la coma como separador decimal al hacer el parseo. El código resultante sería:
public void leerVectorDiscos() throws FileNotFoundException , ParseException     {
        Scanner sc = new Scanner(new File("archivo.txt"));
        String fila;
        String[] vectSt;
        for (int j=0;j<hd.length;j++)
        {
            fila=sc.nextLine();
            vectSt=fila.split("\t");
            hd[j].setTecnologia(vectSt[0]); 
            hd[j].setCapacidad(Integer.parseInt(vectSt[1]));
            Locale spanish = new Locale(“es”, “ES”);
            NumberFormat nf= NumberFormat.getInstance(spanish);
            hd[j].setVelocidad(nf.parse(vectSt[2]).floatValue());
        }
        sc.close();
}

Hay que tener cuidado porque crear una instancia de Locale, no sólo cambia el separador sino también el resto de características asociadas al idioma, como puede ser la moneda o los formatos de fecha y hora.
Una solución alternativa puede ser utilizar un objeto de la clase DecimalFormat, derivada de NumberFormat, que toma la configuración de los números del idioma del sistema operativo que tengamos instalado:
public void leerVectorDiscos() throws FileNotFoundException , ParseException     {
        Scanner sc = new Scanner(new File("archivo.txt"));
        String fila;
        String[] vectSt;
        for (int j=0;j<hd.length;j++)
        {
            fila=sc.nextLine();
            vectSt=fila.split("\t");
            hd[j].setTecnologia(vectSt[0]); 
            hd[j].setCapacidad(Integer.parseInt(vectSt[1]));
            DecimalFormat df= new DecimalFormat();
            hd[j].setVelocidad(df.parse(vectSt[2]).floatValue());
        }
        sc.close();
}

La clase DecimalFormat permite además especificar máscaras, con el formato de presentación que queramos, mediante el constructor, y unos caracteres especificados, con el carácter ‘#’, si el número no tiene una cifra no aparecería, y con el ‘0’, aparecería un ‘0’, por ejemplo:
DecimalFormat df = DecimalFormat(“###.##”);
System.out.println (df.format (2.3));                    //Sacaría 2,3
System.out.println (df.format (2.357));               //Sacaría 2,35
System.out.println (df.format (4322.3));             //Sacaría 4322,3

DecimalFormat df = DecimalFormat(“000.00”);
System.out.println (df.format (2.3));                    //Sacaría 002,30
System.out.println (df.format (2.357));                //Sacaría 002,35
System.out.println (df.format (4322.3));             //Sacaría 4322,3


Existen más caracteres que pueden utilizarse en la máscara, descritos en la API de DecimalFormat.

No hay comentarios:

Publicar un comentario