Validar numero decimal en java

Ha veces es necesario validar si una cadena es decimal o no, por ejemplo cuando el usuario de un programa debe introducir un precio, o el peso de un producto, etc.  El metodo que muestro a continuacion valida si una cadena que le llega es un numero decimal devolviendo true en caso de que si y false en caso de que no.


//Devuelve true si la cadena que llega es un numero decimal, false en caso contrario
 public boolean esDecimal(String cad)
 {
 try
 {
   Double.parseDouble(cad);
   return true;
 }
 catch(NumberFormatException nfe)
 {
   return false;
 }
 }

Basicamente lo que hace este metodo es  intentar convertir la cadena que llega a Decimal con el metodo parseDouble() de la clase Double (este metodo devuelve un dato de tipo double de la cadena que se le pasa como argumento) , si la conversion se puede realiza entonces el metodo devuelve true indicando que si es un numero decimal; por el contrario  si la cadena que se intenta convertir a decimal no tiene la sintaxis correcta de un numero decimal, es decir,  esta linea:

Double.parseDouble(cad);

lanza un excepcion del tipo NumberFormatException,  entonces el metodo se va al catch y devuelve false para indicar que no es un numero decimal. Por otro lado podemos ver que incluso si a la cadena  le llega un entero, por ejemplo:  «544» el metodo devuelve true ( metodo parseDouble devolveria 544.0) , si nos ponemos estrictos podemos ver que 544 no es un numero decimal, ES UN NUMERO ENTERO.  Entonces podemos ver que el metodo realmente lo que hace es verificar si la cadena se puede convertir a decimal, por lo tanto se deberia llamar algo asi como: esConvertibleADecimal(). Otra forma de comprobar si la cadena es un decimal es analizar caracter por caracter para detectar todos los casos en que la cadena pudiera tener un error de sintaxis. El metodo que muestro a continuacion realmente es la implementacion de un automata:


/*
 Descripcion:
 Contiene un metodo que Valida si una cadena es un numero decimal. Se da por hecho que a la
 cadena se le han eliminado posibles espacios al principio y al final
 Author: gonzasilve@gmail.com
 Fecha:  08/12/2009
 archivo CadenaDecimal.java
*/

public class CadenaDecimal
{
 //Devuelve true si la cadena que llega tiene la sintaxis de un decimal
 public boolean esDecimal(String cad)
 {
 boolean hayPunto=false;
 StringBuffer parteEntera = new StringBuffer();
 StringBuffer parteDecimal = new StringBuffer();
 int i=0, posicionDelPunto;

 for( i=0;i<cad.length(); i++ )
 if ( cad.charAt(i) == '.')                          //Detectar si hay un punto decimal en la cadena
 hayPunto=true;
 if(hayPunto)                                            //Si hay punto guardar la posicion donde se encuentra el carater punto
 posicionDelPunto=cad.indexOf('.');                  //(si la cadena tiene varios puntos, detecta donde esta el primero).
 else
 return false;                                       //Si no hay punto; no es decimal

 if( posicionDelPunto == cad.length()-1 || posicionDelPunto== 0)    //Si el punto esta al final o al principio no es un decimal
 return false;

 for( i=0;i<posicionDelPunto; i++ )
 parteEntera.append(cad.charAt(i)) ;                 //Guardar la parte entera en una variable

 for(i = 0; i<parteEntera.length(); i++)
 if( ! Character.isDigit(parteEntera.charAt(i)) )    //Si alguno de los caracteres de la parte entera no son digitos no es decimal
 return false;

 for( i=posicionDelPunto+1;i<cad.length(); i++ )
 parteDecimal.append(cad.charAt(i));                 //Guardar la parte decimal en una variable

 for(i = 0; i<parteDecimal.length(); i++)
 if( ! Character.isDigit(parteDecimal.charAt(i)) )   //Si alguno de los caracteres de la parte decimal no es un digito no es decimal
 return false;                                   //Incluye el caso en el que la cadena tenga dos o mas puntos

 return true;                                            //Si paso todas las pruebas anteriores, la cadena es un Numero decimal
 }

    public static void main(String args[])
    {
      CadenaDecimal prueba1 = new CadenaDecimal();
      //Devuelve true
      System.out.println("Cadena \"324.40\" es decimal: "+prueba1.esDecimal("324.40"));
      //Devuelve false
      System.out.println("Cadena \"324.6a\" es decimal: "+prueba1.esDecimal("324.6a"));
      //Devuelve false
      System.out.println("Cadena \"3a4.00\" es decimal: "+prueba1.esDecimal("3a4.00"));
      //Devuelve false
      System.out.println("Cadena \"3a4\" es decimal: "+prueba1.esDecimal("3a4"));
      //Devuelve false, es un entero
      System.out.println("Cadena \"656\" es decimal: "+prueba1.esDecimal("656"));
    }
}

Este metodo es mas estricto y no acepta el «544», devuelve false pues 544 no es un decimal, ES UN ENTERO. A continuacion muestro una imagen de la compilacion y ejecucion de este metodo:

A continuacion explico un poco el codigo, esta parte:

 for( i=0;i<cad.length(); i++ )
 if ( cad.charAt(i) == '.')                          //Detectar si hay un punto decimal en la cadena
 hayPunto=true;

Detecta si hay un punto dentro de la cadena, las cadenas «23.213» , «4g21.12», «.232» , «dwe.23», «434.» , «465..2ew», «.45dsd34», «87.232…» pondrian la variable hayPunto en true, pues todas estas cadenas tienen un punto.

despues el siguiente codigo:

 if(hayPunto)                                            //Si hay punto guardar la posicion donde se encuentra el carater punto
 posicionDelPunto=cad.indexOf('.');                  //(si la cadena tiene varios puntos, detecta donde esta el primero).
 else
 return false;                                       //Si no hay punto; no es decimal

verifica si hay un punto se recoge la posicion (el indice) en donde esta esta ese punto dentro de la cadena. Si no hay punto entonces se devuelve false para indicar que la cadena no es un decimal, pues todos los numeros decimales tienen un punto decimal ¿ o no?.

despues el siguiente codigo:

 if( posicionDelPunto == cad.length()-1 || posicionDelPunto== 0)    //Si el punto esta al final o al principio no es un decimal
 return false;

verifica si el punto esta al final o (||) si el punto esta al principio devuelve false, pues los numeros decimales no tiene el punto decimal al principio, en este caso somos muy estrictos y no se aceptan cadenas como «.547» (lleva implicito un cero como parte entera), el metodo devolveria false, por que no se acepta que el usuario piense que el sistema le va a colocar el cero como parte entera. Todo lo demas ya esta explicado en el codigo, asi que ya no lo explico mucho.

Lo siguiente es comprobar si la parte entera (los caracteres que estan antes del punto) todos son digitos enteros, si alguno no lo es entonces devolver false para indicar que no es un decimal, «67sa5.76» no es un decimal ¿o si?.

 for( i=0;i<posicionDelPunto; i++ )
 parteEntera.append(cad.charAt(i)) ;                 //Guardar la parte entera en una variable

 for(i = 0; i<parteEntera.length(); i++)
 if( ! Character.isDigit(parteEntera.charAt(i)) )    //Si alguno de los caracteres de la parte entera no son digitos no es decimal
 return false;

El codigo anterior es el mismo que se uso en la implementacion del metodo para validar numero entero.

Lo siguiente es comprobar si la parte decimal (los caracteres que estan despues del punto) todos son digitos enteros, si alguno no lo es entonces devolver false para indicar que no es un decimal, «6757.8766», «6757..8766» no son decimales ¿o si?.


 for( i=posicionDelPunto+1;i<cad.length(); i++ )
 parteDecimal.append(cad.charAt(i));                 //Guardar la parte decimal en una variable

 for(i = 0; i<parteDecimal.length(); i++)
 if( ! Character.isDigit(parteDecimal.charAt(i)) )   //Si alguno de los caracteres de la parte decimal no es un digito no es decimal
 return false;                                   //Incluye el caso en el que la cadena tenga dos o mas puntos

por ultimo se devuelve un true si la cadena pudo pasar por toda las serie de pruebas anteriores. SI las paso es por que la cadena tiene toda la sintaxis de un numero decimal correctamente escrito.

 return true;        //Si paso todas las pruebas anteriores, la cadena es un Numero decimal

… hasta pronto.
}