10 razones por las que tu código Java no compila (I)

¿Sabes por qué tu código Java no compila con echar un solo vistazo?

Si tu código Java no compila, ¿sabes analizarlo? Pero sin utilizar un IDE, oye. Así, cualquiera.

More...

Si tu código Java no compila, el IDE te lo chiva

En este ejemplo, en el código aparece una llamada al método moveHistorial(boolean), pero sin ningún argumento. Aunque aquí es fácil verlo, ya que el método llamado se encuentra justo a continuación, en un proyecto más grande no va a estar tan a la vista. Pero, de todas formas, el IDE te lo chiva.

En el examen, en cambio, no vas a poder utilizar ningún IDE: vas a tener delante de ti un fragmento de código, con varias opciones entre las que escoger, y es muy posible que una de ellas sea "el código no compila", así, en general, sin especificar una línea. Entonces, ¿qué?

Qué opciones aparecen en el examen cuando el código Java no compila

Como ya te he comentado en otros artículos, es posible que en el examen te topes con una pregunta que parezca orientada hacia las lambdas pero que, en realidad, te esté poniendo a prueba, porque el código lanza una excepción antes de llegar a la lambda.

Con los errores de compilación no pasa esto. Es decir, si todas las opciones de respuesta a la pregunta dan por supuesto que el código compila, es porque va a compilar. No obstante, es posible que te encuentres con opciones como las siguientes:

  • "La línea 7 (u 8, 10, etc) no compila"

Puede que te aparezcan varias opciones con distintos números de línea en una misma pregunta. En este caso, fíjate si las líneas citadas compilan.

  • "El código no compila", o "ninguna de las anteriores"

En estos dos casos deberás revisar todo el código; la primera opción, "el código no compila", deja abierta la posibilidad; la segunda, "ninguna de las anteriores", deja la puerta abierta a cualquier cosa (y es una opción bastante jodida, porque te obliga a pensar en todo).

El código Java no compila: qué mirar cuando no sabes qué mirar

Supongamos, entonces, que te encuentras con una de esas opciones en el examen. A partir de ese momento tienes que analizar el código como si fueras el compilador. ¿Y en qué se fija el compilador? A continuación te enumero diez puntos en lo que te tendrás que fijar en el examen de certificación para saber si tu código compila.

10 razones por las que tu código Java no compila (con ejemplos)

10 razones por las que tu código java no compila

10 razones por las que tu código #Java no compila: lo que tienes que saber para el examen #OCA

Compártelo

1._ Llamada a un método que no existe

Fíjate que en el código que estás analizando no haya ninguna llamada a un método que no existe.

  • ¿Coincide el nombre del método?
  • ¿Coincide la lista de parámetros con la de argumentos?

Asegúrate de que la llamada reproduce correctamente el nombre del método, y que la lista de argumentos de la llamada coincida con la lista de parámetros del método. Ten cuidado con los métodos sobrecargados y con los métodos heredados; no olvides que no se puede llamar un método no estático desde un método estático.

2._ El código no importa los paquetes necesarios

En relación con el punto anterior, ¿aparecen en el texto métodos para los que es necesario hacer un import? Fíjate si el código está numerado. Si lo está, deberían estar todos los import necesarios.

  • Haz una lista de todos los imports que aparecen en el manual que estés utilizando. Por ejemplo, LocalDateTime, List<> o IOException requieren su propio import.

3._ Uso de una variable o referencia no declarada

Fíjate que todas las variables o referencias que se utilizan estén declaradas. La declaración ha de ser anterior a su uso.

4._ Uso de una variable o referencia sin asignar

Aquí, depende. Es posible, en ciertas ocasiones, hacer uso de una variable a la que no se le ha asignado un valor, o de una referencia a la que no se le ha asignado un objeto.

Ten en cuenta que el compilador no tiene en cuenta el valor asignado a una variable, si esta no está marcada como final.

Tipos primitivos

Si la variable forma parte de un objeto (es decir, es un campo de clase), toma un valor predeterminado si no le asigna ninguno. Así, de un modo u otro siempre contiene un valor.

  • La asignación de una variable que forma parte de un objeto puede ser explícita o implícita (posee un valor predeterminado).

Si la variable es local, es decir, si aparece dentro de un método, no posee un valor de manera predeterminada. Si existe una variable sin asignar, todo irá bien siempre y cuando no se haga nada con esa variable. En el momento en el que quieras utilizarla, aunque sea para imprimirla, el código no va a compilar.

  • La asignación de una variable local ha de ser explícita.

Así, la asignación de una variable local ha de ser explícita. Si a la variable se le asigna un valor de manera dinámica y según una condición, esta asignación tampoco le vale al compilador, aunque la condición se cumpla. 

Puedes resolver este problema marcando como final la variable que se evalúa en la condición (en ese caso, el compilador sí tiene en cuenta su valor) o asígnandole otro valor a la variable de no cumplirse la condición (así, en cualquier caso se le asigna un valor).

  • El compilador no tiene en cuenta el valor asignado a una variable, a no ser que esta sea final.

Referencias

Con una referencia puede ocurrir tres cosas:

  • Que no tenga ningún objeto asignado. En este caso, el código no compila. Si pretendes asignarle un valor mediante una condición, como con las variables, el truco de marcar como final la referencia evaluada no funciona.
  • Que esté inicializada como null. Es decir, que, de manera explícita, se exprese que la referencia no apunta a ningún objeto, o que, de manera implícita, tome este valor porque es un campo de clase. En este caso, solo puedes ejecutar con esta referencia métodos estáticos
  • Que apunte a un objeto. En este caso, todo bien.

5._ Parte del código no llega a ejecutarse

Me refiero a que parte del código no llega a ejecutarse en ningún caso. Por ejemplo, si un método devuelve un valor, no puede haber código después del return. Si hay un return dentro de un switch o una estructura if/else, habrá de cumplirse una de las dos condiciones que siguen:

  • Que, sea cual sea la variable o referencia que se evalúe, haya un return al final (en un switch, incluyendo la opción default; en un if/else, incluir un else sin condición específica).
  • Si no se tienen en cuenta todos los valores que puede tomar la variable o referencia evaluada, ha de haber un return al final del método.

Ve probando varias combinaciones. Por supuesto, existen al menos tres excepciones a esta regla:

  • El catch de un try/catch puede no ejecutarse.
  • System.exit(0); detiene la ejecución del programa, pero compila sin problemas.
  • if(false){} es válido.

6._ Un método no devuelve el tipo apropiado

De nuevo, tenemos dos casos: si el método devuelve un tipo primitivo, o si devuelve una referencia a un objeto. En pocas palabras, el método puede devolver el valor que aparece explícito en su signatura, u otro más pequeño. A continuación te explico qué quiero decir con eso de más pequeño.

Tipos primitivos

Un método ha de devolver o el mismo tipo primitivo que aparezca en su signatura, o un tipo compatible. Es decir, si devuelve un int, no puede devolver un double. En cambio, si devuelve un double, sí puede devolver un int. Échale un ojo a los artículos que he publicado sobre tipos primitivos.

No obstante, si la devolución es la clase envoltorio de un primitivo (Integer, Double, Boolean, Long, Float, Character, Short, Byte) solo podrás devolver ese mismo primitivo o su envoltorio. Es decir, si la devolución es Double, no es válido devolver un int. Solo double o Double.

Referencias

Un método ha de devolver una referencia del mismo tipo que la que aparece en su signatura, o de una subclase. Es decir, si según la signatura el método devuelve List<String>, es válido devolver ArrayList<String>.

Este punto, el número 6, también es válido en lo que respecta a los argumentos que admite un método: los argumentos han de ser del mismo tipo que los parámetros de la signatura, o compatibles. Además, han de aparecer en el mismo orden.

7._ Asignación errónea de la devolución de un método

Este punto está vinculado al anterior. Resulta que, esta vez, la signatura del método especifica que devuelve un double; el método devuelve un int, y la devolución se asigna a una variable de tipo int. Resultado: no compila.

De nuevo, no puedes asignar un tipo primitivo a un objeto envoltorio de otro primitivo: no puedes asignar int a Double.

¿Saves por qué no compila en este caso?

8._ Reasignación de variables o referencias marcadas como final

No se pueden reasignar una variable o una referencia marcados como final.

  • Si se encuentra dentro de un método, se les ha de asignar el valor de inmediato.
  • Si forman parte de un objeto, se les puede asignar un valor también en un bloque estático o en el constructor.

En cambio, sí puedes modificar, por ejemplo, el contenido de un List marcado como final. Lo que no puedes es asignar su referencia a otro List.

9._ Cuidado con el constructor predeterminado

El constructor predeterminado solo existe cuando no existe un constructor explícito. Es decir, si la clase no posee un constructor, es posible instanciar esa clase mediante una llamada a un constructor sin argumentos.

En este ejemplo, como ves, hay un método que parece ser un constructor, pero que no lo es. Para instanciar la clase hay que utilizar el constructor predeterminado. Parece que este ejemplo de código Java no compila, pero sí que lo hace.

Recuerda que el constructor NUNCA tiene un valor de devolución.

En los casos en los que tengas delante varias clases en una jerarquía de herencia, recuerda que las clases se instancian desde la superclase hacia abajo, y que cada constructor posee una llamada, ya sea implícita (super();) o explícita, al constructor de la superclase.

El constructor implícito de C hace una llamada al constructor sin argumentos de B. Como el constructor de A tiene un parámetro, la llamada al constructor de A desde el constructor de B ha de ser explícito.

10._ Error de sintaxis

Este punto está bien claro: cuando tengas varios if/else o bucles anidados, fíjate en que no falte ninguna llave de cierre ni paréntesis; que todos los punto y coma estén en su sitio al final de cada línea, es decir, que la sintaxis sea correcta.

Y esto no es todo, amigos

¿Qué te ha parecido la lista? ¿Sabes ya por qué tu código Java no compila? Tranquilo, la semana que viene continuaré con esta lista, ya que me he dejado varios casos más en el tintero. Mientras tanto, practica todos estos ejemplos, ¡y acostúmbrate a leer mucho código!

Deja una respuesta 0 comentarios