varios try catch en un mismo código

Iniciado por juligarc10, 19 Febrero 2019, 11:43 AM

0 Miembros y 1 Visitante están viendo este tema.

juligarc10

Hola amigos. Tengo un problema.
Estoy intentando diseñar un código en el cual se recojan las exceptiones con try catch, pero a la vez que las recojo, si estas excepciones aparecen, deberá de pedirse otra vez el código con un do while hasta que lo introducido sea correcto. Me explico:

do{
            try{
        System.out.print("Nombre del cliente ");
        if (c.getNombre().length() > 0) {
            System.out.print("[" + c.getNombre() + "]");
        }
       
       
        System.out.print(": ");
        info = teclado.nextLine().trim();
        if (info.length()<=0||isNumeric(info)==true){
            throw new Exception("Debe introducir un nombre");
        }
       
            }catch(Exception exc){
                System.err.println( "ERROR:\n "+exc.getMessage());
            }
        }while(info.length()<=0||isNumeric(info)==true);

        if (info.length() > 0) {
            c.setNombre(info);
        }

        // D.N.I.
        do{
        try{
        System.out.print("D.N.I. del cliente ");
        if (c.getDni().length() > 0) {
            System.out.print("[" + c.getDni() + "]");
        }
        System.out.print(": ");
        info = teclado.nextLine().trim();
        if (info.length()<=0||isNumeric(info)==false){
            throw new Exception("Debe introducir un dni");
        }
        }catch(Exception e){
            System.err.println("ERROR:\n "+e.getMessage());
        }
        if (info.length() > 0) {
            c.setDni(info);
        }
        while(info.length()<=0||isNumeric(info)==false);

       


Mi idea es hacerlo realizando varios try, cada uno dentro de su do/while. No se me ocurre otra manera de hacerlo más óptimo. ¿La hay?
El otro problema es que el código, haciéndolo de esta manera no me funciona. Las excepciones las recoge bien, pero una vez le metes un código que en teoría es válido, lanza una excepcion llamada "java.lang.RuntimeException: Uncompilable source code".
El tema es que si yo solo tengo habilitado un try catch, el código si funciona perfectamente, así:
// Nombre
        do{
            try{
        System.out.print("Nombre del cliente ");
        if (c.getNombre().length() > 0) {
            System.out.print("[" + c.getNombre() + "]");
        }
       
       
        System.out.print(": ");
        info = teclado.nextLine().trim();
        if (info.length()<=0||isNumeric(info)==true){
            throw new Exception("Debe introducir un nombre");
        }
       
            }catch(Exception exc){
                System.err.println( "ERROR:\n "+exc.getMessage());
            }
        }while(info.length()<=0||isNumeric(info)==true);

        if (info.length() > 0) {
            c.setNombre(info);
        }

        // D.N.I.
        /*do{
        try{
        System.out.print("D.N.I. del cliente ");
        if (c.getDni().length() > 0) {
            System.out.print("[" + c.getDni() + "]");
        }
        System.out.print(": ");
        info = teclado.nextLine().trim();
        if (info.length()<=0||isNumeric(info)==false){
            throw new Exception("Debe introducir un dni");
        }
        }catch(Exception e){
            System.err.println("ERROR:\n "+e.getMessage());
        }
        if (info.length() > 0) {
            c.setDni(info);
        }
        while(info.length()<=0||isNumeric(info)==false);*/


¿Alguna idea gente? Gracias de antemano, y un saludo.

juligarc10

Hola gente, ya he conseguido hacer que funcione, pero de todas formas, saben si hay algun metodo más eficiente? Gracias.

Serapis

#2
La forma de optimizarlo es parametrizarlo en una función, que se invoque para cada consulta que se precise....

string = funcion Solicitar(string msgPeticion, entero minSize, entero maxSize, buleano soloDigitos, ...)
   buleano ok, rep = false
   string Salida = ""

   Hacer
       mostrar(msgPeticion)
       salida =PedirEntrada
       
       Si ((minSize >0) o (maxSize >0))
           Si (minSize >0)
               si (salida.length < minSize)
                   mostrar("error, debe tener al menos" + minSize + " caracteres...")  
               fin si
           fin si
           Si (maxSize >0)
               si (salida.length > maxSize)
                   mostrar("error, debe tener como máximo" + maxSize + " caracteres...")
               fin si
           fin si
       Fin si

       Si (soloDigitos = TRUE)
           rep = false
           por cada caracter  en salida
               Si (caracter <> digito)
                   mostrar("error, solo se permiten dígitos...")  
                   rep = TRUE  
                   salir del bucle for
               fin si
           Siguiente en bucle  
           si (rep = False)
               OK = TRUE  
           fin si
       Sino
           OK = TRUE
       Fin si  
   repetir mientras (ok=False)

   devolver Salida
fin funcion



Llamada de uso de la función...

string DNI = Solicitar("Ingrese su DNI", 8, 8, TRUE)  //se solicitan 8 caracteres y deben ser todos dígitos.
objeto.setDNI(DNI)


Algo que no haces correctamente es usar bloques 'Try Catch', alegremente... dichos bloques deben usarse para interceptar errores no tratados en el código (por ejemplo intentar acceder a una unidad de solo lectura con intención de escribir, tu no puedes evitar que si pretendes escribir un fichero el usuario te derive a una unidad de solo lectura, o bien si pero con demasiado código, un bloque try catch, resuelve mucho código en una simple intervención)...pero no para errores para los que precisamente estás interceptando...

Máxime considerando que la interacción con el usuario no se puede considerar un error: si le pides x caracteres, y él los escribe, que tú no los aceptes, no implica un 'error' implica que no se ha validado la entrada... En resumen no fuerces un error inexistente, no ganas nada con ello, excepto complicarte las barbas innecesariamente.

Los bloques Try Catch, existen para intentar salir adelante con errores no interceptados (porque quizás fueren tantos y tan diversos que "sería infinito el código para sumergirse en una aventura", así un bloque Try Catch, permite resumir toda esa aventura en un 'si falla algo dame pistas y si fueran ciertos simples y conocidos vemos de solventarlo... y seguir adelante en vez de dar por terminado el programa.
...pero vamos el error más grave que cometes, es inmiscuir al usuario con errores, como si él mismo fuera un programador o como si tuviera que saber determinados detalles que ni le van ni le vienen. Tu solo le nformas de lo que precisas 'dame el DNI', y si contiene caracteres ilegales, le sueltas un 'repite, porque hay caracteres extraños y solo debe tener dígitos'.... como es una simple comprobación que tienes que hacer si o sí, conoces el problema y entonces el bloque try catch, resulta usado en abuso.

El programador todavía debe generar errores, en situaciones donde él mismo u otro que utilice el componente que has realizado, genere rsultados erróneos. Por ejemplo, si creas un objeto que solicite una entrada al usuario y la deuelve sin procesar, y dicho objeto tenía un parámetro de 'solo dígitos', está bien que generes un error para que el objeto que lo reciba sepa que debe tratarlo, así el objeto que lo recibe puede mostrar el mensaje oportuno al usuario y volver a solicitarlo, o si le es posible ignorarlo, seguir adelante...
...por ejemplo, supongamos que se pide el dni, y el usuario escribió: 88555222H se soluciona el problema si se retira la 'H', o incluso se le podía preguntar: confirme si es éste el numero correcto: 88555222 sin la 'H', que es el carácter no válido, otro ejemplo: 88sd@45, como hay que eliminar más de 1 carácter y sigue sin tener el largo esperado de dígitos, procede mejor solicitar que se ingrese de nuevo?).


Forzando el mismo pseudocódigo previo, como 2 objetos distintos, donde el primero es un servicio que utiliza el segundo... que ahí si tendría sentido un try catch.

string = funcion Solicitar(string msgPeticion, entero minSize, entero maxSize, buleano soloDigitos, ...)
   string Salida = ""

   mostrar(msgPeticion)
   salida =PedirEntrada
   
   Si ((minSize >0) o (maxSize >0))
       Si (minSize >0)
           si (salida.length < minSize)
               disparar error SizeIlegal
               //devolver error  el código sale desde la línea previa, es equivalente a devolver el error.
           fin si
       fin si
       Si (maxSize >0)
           si (salida.length > maxSize)
               disparar error SizeIlegal
               //devolver error  el código sale desde la línea previa, es equivalente a devolver el error.
           fin si
       fin si
   Fin si

   Si (soloDigitos = TRUE)
       por cada caracter  en salida
           Si (caracter <> digito)
               disparar error CaracterIlegal
               //devolver error el código sale desde la línea previa, es equivalente a devolver el error.
           fin si
       siguient en bucle  
   Fin si  

   devolver Salida
fin funcion


Lo previo sería el código de una función dentro de un objeto, se ve que es casi identico al previo, excepto que no está en un bucle, e intercepta dos tipos de errores, que comunicará al objeto cliente.

Llamada de uso de la función...

Do
   Try
       string DNI = servicio.Solicitar("Ingrese su DNI", 8, 8, TRUE)  //se solicitan 8 caracteres y deben ser todos dígitos.
       objeto.setDNI(DNI)
   Catch (excepcion)
       Si (excepcion= SizeIlegal)
           MostrarMensaje("debe tener 8 caracteres, ni más ni menos")
       OSi (excepcion= CaracterIlegal)
           MostrarMensaje("Solo debe contener dígitos")
       Fin si
   End try
Loop while excepcion



Como puedes ver ambos códigos son muy similares... pero hay claras diferencias... en el primero, tú controlas todos, porque está todo en el mismo objeto, conoces los posibleserrores, porque sabes lo que eseras, luego no proceder generar errores.
En cambio en este segundo ejemplo (es básicamente lo msmo que el previo), la función 'Solictar' yace en otro objeto distinto de tú código, al que tu invocas... aquel método, simplemente genera  un mensaje bajo ciertas condiciones y está capacitado para arrojar un error si no se cumplen, pero allí a diferencia del ejemplo previo, no tiene un bucle... quien sabe si el programador quisiera darle al usuario la opción de abortar?... en cambio tú ahora en tu código si debes tratar las excepciones, pero nota que las excepciones se dan de cara al código, con el que el programador debe lifdiar, no al usuario...

En fin, la línea es delgadita, sibilina, pero es importante percibirla con clardad. Repasa cuantas veces sea ambos códigos con los comentarios hasta que percibas claramente la diferencia entre ellas y el porqué del asunto.



P.D.: Nota por último, como lo importante de dicha función (sobre otro objeto) es que luego permite simplificar enormemente la operatoria de verificación... simplemente haces una llamada y verificas las posibles excepciones... (si hubiere muchas más, sacas un mensaje genérico sobre como se espera que sea lo correcto), pero no precisas hacer para cada ppeticion, DNI, nombre, Calle, Número de calle o piso, etc... toda esa operatoria, que sería mucho código. Además de más breve, resulta mucho más legible, porque la propia función 'Solicitar' queda encapsulada en otro objeto...
Nota también que para atrapar los diferentes aspectos en que pudieran incurrir todos esos mensajes deben ser parametrizados y tratados en la funcón, yo solo he puesto de ejemplo el tamaño mínimo y máximo de caracteres y en que se permitan solo dígitos... pero habrá más casos.

juligarc10

Cita de: NEBIRE en 19 Febrero 2019, 14:04 PM
La forma de optimizarlo es parametrizarlo en una función, que se invoque para cada consulta que se precise....

string = funcion Solicitar(string msgPeticion, entero minSize, entero maxSize, buleano soloDigitos, ...)
   buleano ok, rep = false
   string Salida = ""

   Hacer
       mostrar(msgPeticion)
       salida =PedirEntrada
       
       Si ((minSize >0) o (maxSize >0))
           Si (minSize >0)
               si (salida.length < minSize)
                   mostrar("error, debe tener al menos" + minSize + " caracteres...")  
               fin si
           fin si
           Si (maxSize >0)
               si (salida.length > maxSize)
                   mostrar("error, debe tener como máximo" + maxSize + " caracteres...")
               fin si
           fin si
       Fin si

       Si (soloDigitos = TRUE)
           rep = false
           por cada caracter  en salida
               Si (caracter <> digito)
                   mostrar("error, solo se permiten dígitos...")  
                   rep = TRUE  
                   salir del bucle for
               fin si
           Siguiente en bucle  
           si (rep = False)
               OK = TRUE  
           fin si
       Sino
           OK = TRUE
       Fin si  
   repetir mientras (ok=False)

   devolver Salida
fin funcion



Llamada de uso de la función...

string DNI = Solicitar("Ingrese su DNI", 8, 8, TRUE)  //se solicitan 8 caracteres y deben ser todos dígitos.
objeto.setDNI(DNI)


Algo que no haces correctamente es usar bloques 'Try Catch', alegremente... dichos bloques deben usarse para interceptar errores no tratados en el código (por ejemplo intentar acceder a una unidad de solo lectura con intención de escribir, tu no puedes evitar que si pretendes escribir un fichero el usuario te derive a una unidad de solo lectura, o bien si pero con demasiado código, un bloque try catch, resuelve mucho código en una simple intervención)...pero no para errores para los que precisamente estás interceptando...

Máxime considerando que la interacción con el usuario no se puede considerar un error: si le pides x caracteres, y él los escribe, que tú no los aceptes, no implica un 'error' implica que no se ha validado la entrada... En resumen no fuerces un error inexistente, no ganas nada con ello, excepto complicarte las barbas innecesariamente.

Los bloques Try Catch, existen para intentar salir adelante con errores no interceptados (porque quizás fueren tantos y tan diversos que "sería infinito el código para sumergirse en una aventura", así un bloque Try Catch, permite resumir toda esa aventura en un 'si falla algo dame pistas y si fueran ciertos simples y conocidos vemos de solventarlo... y seguir adelante en vez de dar por terminado el programa.
...pero vamos el error más grave que cometes, es inmiscuir al usuario con errores, como si él mismo fuera un programador o como si tuviera que saber determinados detalles que ni le van ni le vienen. Tu solo le nformas de lo que precisas 'dame el DNI', y si contiene caracteres ilegales, le sueltas un 'repite, porque hay caracteres extraños y solo debe tener dígitos'.... como es una simple comprobación que tienes que hacer si o sí, conoces el problema y entonces el bloque try catch, resulta usado en abuso.

El programador todavía debe generar errores, en situaciones donde él mismo u otro que utilice el componente que has realizado, genere rsultados erróneos. Por ejemplo, si creas un objeto que solicite una entrada al usuario y la deuelve sin procesar, y dicho objeto tenía un parámetro de 'solo dígitos', está bien que generes un error para que el objeto que lo reciba sepa que debe tratarlo, así el objeto que lo recibe puede mostrar el mensaje oportuno al usuario y volver a solicitarlo, o si le es posible ignorarlo, seguir adelante...
...por ejemplo, supongamos que se pide el dni, y el usuario escribió: 88555222H se soluciona el problema si se retira la 'H', o incluso se le podía preguntar: confirme si es éste el numero correcto: 88555222 sin la 'H', que es el carácter no válido, otro ejemplo: 88sd@45, como hay que eliminar más de 1 carácter y sigue sin tener el largo esperado de dígitos, procede mejor solicitar que se ingrese de nuevo?).


Forzando el mismo pseudocódigo previo, como 2 objetos distintos, donde el primero es un servicio que utiliza el segundo... que ahí si tendría sentido un try catch.

string = funcion Solicitar(string msgPeticion, entero minSize, entero maxSize, buleano soloDigitos, ...)
   string Salida = ""

   mostrar(msgPeticion)
   salida =PedirEntrada
   
   Si ((minSize >0) o (maxSize >0))
       Si (minSize >0)
           si (salida.length < minSize)
               disparar error SizeIlegal
               //devolver error  el código sale desde la línea previa, es equivalente a devolver el error.
           fin si
       fin si
       Si (maxSize >0)
           si (salida.length > maxSize)
               disparar error SizeIlegal
               //devolver error  el código sale desde la línea previa, es equivalente a devolver el error.
           fin si
       fin si
   Fin si

   Si (soloDigitos = TRUE)
       por cada caracter  en salida
           Si (caracter <> digito)
               disparar error CaracterIlegal
               //devolver error el código sale desde la línea previa, es equivalente a devolver el error.
           fin si
       siguient en bucle  
   Fin si  

   devolver Salida
fin funcion


Lo previo sería el código de una función dentro de un objeto, se ve que es casi identico al previo, excepto que no está en un bucle, e intercepta dos tipos de errores, que comunicará al objeto cliente.

Llamada de uso de la función...

Do
   Try
       string DNI = servicio.Solicitar("Ingrese su DNI", 8, 8, TRUE)  //se solicitan 8 caracteres y deben ser todos dígitos.
       objeto.setDNI(DNI)
   Catch (excepcion)
       Si (excepcion= SizeIlegal)
           MostrarMensaje("debe tener 8 caracteres, ni más ni menos")
       OSi (excepcion= CaracterIlegal)
           MostrarMensaje("Solo debe contener dígitos")
       Fin si
   End try
Loop while excepcion



Como puedes ver ambos códigos son muy similares... pero hay claras diferencias... en el primero, tú controlas todos, porque está todo en el mismo objeto, conoces los posibleserrores, porque sabes lo que eseras, luego no proceder generar errores.
En cambio en este segundo ejemplo (es básicamente lo msmo que el previo), la función 'Solictar' yace en otro objeto distinto de tú código, al que tu invocas... aquel método, simplemente genera  un mensaje bajo ciertas condiciones y está capacitado para arrojar un error si no se cumplen, pero allí a diferencia del ejemplo previo, no tiene un bucle... quien sabe si el programador quisiera darle al usuario la opción de abortar?... en cambio tú ahora en tu código si debes tratar las excepciones, pero nota que las excepciones se dan de cara al código, con el que el programador debe lifdiar, no al usuario...

En fin, la línea es delgadita, sibilina, pero es importante percibirla con clardad. Repasa cuantas veces sea ambos códigos con los comentarios hasta que percibas claramente la diferencia entre ellas y el porqué del asunto.



P.D.: Nota por último, como lo importante de dicha función (sobre otro objeto) es que luego permite simplificar enormemente la operatoria de verificación... simplemente haces una llamada y verificas las posibles excepciones... (si hubiere muchas más, sacas un mensaje genérico sobre como se espera que sea lo correcto), pero no precisas hacer para cada ppeticion, DNI, nombre, Calle, Número de calle o piso, etc... toda esa operatoria, que sería mucho código. Además de más breve, resulta mucho más legible, porque la propia función 'Solicitar' queda encapsulada en otro objeto...
Nota también que para atrapar los diferentes aspectos en que pudieran incurrir todos esos mensajes deben ser parametrizados y tratados en la funcón, yo solo he puesto de ejemplo el tamaño mínimo y máximo de caracteres y en que se permitan solo dígitos... pero habrá más casos.

Muchas gracias amigo. Me fue de gran ayuda tu comentario ;-)

Un saludo.