¿Hubo alguna razón por la que los diseñadores de Java sintieron que a las variables locales no se les debería dar un valor predeterminado? En serio, si a las variables de instancia se les puede dar un valor predeterminado, ¿por qué no podemos hacer lo mismo con las variables locales?
Y también conduce a problemas como se explica en este comentario a una publicación de blog :
Bueno, esta regla es más frustrante cuando se intenta cerrar un recurso en un bloque final. Si creo una instancia del recurso dentro de un intento, pero trato de cerrarlo en el final, aparece este error. Si muevo la instanciación fuera del intento, aparece otro error que indica que debe estar dentro de un intento.
Muy frustrante.
java
variables
initialization
Shivasubramanian A
fuente
fuente
Respuestas:
Las variables locales se declaran principalmente para hacer algunos cálculos. Entonces, es decisión del programador establecer el valor de la variable y no debe tomar un valor predeterminado. Si el programador, por error, no inicializó una variable local y toma un valor predeterminado, entonces la salida podría ser un valor inesperado. Entonces, en el caso de las variables locales, el compilador le pedirá al programador que inicialice con algún valor antes de acceder a la variable para evitar el uso de valores indefinidos.
fuente
El "problema" al que enlaza parece describir esta situación:
La queja del comentarista es que el compilador se resiste a la línea de la
finally
sección, alegando queso
podría no estar inicializada. El comentario luego menciona otra forma de escribir el código, probablemente algo como esto:El comentarista no está satisfecho con esa solución porque el compilador dice que el código "debe estar en un intento". Supongo que eso significa que parte del código puede generar una excepción que ya no se maneja. No estoy seguro. Ninguna versión de mi código maneja excepciones, por lo que cualquier cosa relacionada con la excepción en la primera versión debería funcionar igual en la segunda.
De todos modos, esta segunda versión de código es la forma correcta de escribirlo. En la primera versión, el mensaje de error del compilador era correcto. Es
so
posible que la variable no esté inicializada. En particular, si elSomeObject
constructor falla,so
no se inicializará, por lo que será un error intentar llamarso.CleanUp
. Entra siempre en latry
sección después de haber adquirido el recurso quefinally
finaliza la sección.El bloque
try
-finally
después de laso
inicialización está ahí solo para proteger laSomeObject
instancia, para asegurarse de que se limpie sin importar lo que suceda. Si hay otras cosas que deben ejecutarse, pero no están relacionados a si laSomeObject
instancia se asignó la propiedad, entonces deben ir en otratry
-finally
bloque, probablemente uno que envuelve la que yo he mostrado.Exigir que las variables se asignen manualmente antes de su uso no genera problemas reales. Solo conduce a problemas menores, pero su código será mejor para eso. Vas a tener variables con alcance más limitado, y
try
-finally
los bloques que no tratan de proteger demasiado.Si las variables locales tuvieran valores predeterminados, entonces
so
en el primer ejemplo habría sidonull
. Eso realmente no habría resuelto nada. En lugar de obtener un error en tiempo de compilación en elfinally
bloque, tendrías unNullPointerException
acecho allí que podría ocultar cualquier otra excepción que pudiera ocurrir en la sección "Trabaja un poco aquí" del código. (¿O las excepciones en lasfinally
secciones se encadenan automáticamente a la excepción anterior? No recuerdo. Aun así, tendrías una excepción adicional en el camino de la real).fuente
Además, en el siguiente ejemplo, es posible que se haya lanzado una excepción dentro de la construcción SomeObject, en cuyo caso la variable 'so' sería nula y la llamada a CleanUp arrojará una NullPointerException
Lo que tiendo a hacer es esto:
fuente
Tenga en cuenta que las variables de instancia / miembro finales no se inicializan de forma predeterminada. Porque esos son definitivos y no se pueden cambiar en el programa posteriormente. Esa es la razón por la que Java no les da ningún valor predeterminado y obliga al programador a inicializarlo.
Por otro lado, las variables de miembros no finales se pueden cambiar más tarde. Por lo tanto, el compilador no permite que permanezcan sin inicializar, precisamente, porque se pueden cambiar más tarde. En cuanto a las variables locales, el alcance de las variables locales es mucho más estrecho. El compilador sabe cuándo se está utilizando. Por lo tanto, tiene sentido forzar al programador a inicializar la variable.
fuente
La respuesta real a su pregunta es porque las variables de método se instancian simplemente agregando un número al puntero de la pila. Ponerlos a cero sería un paso más. Para las variables de clase, se colocan en la memoria inicializada en el montón.
¿Por qué no dar un paso más? Dé un paso atrás - Nadie mencionó que la "advertencia" en este caso es algo muy bueno.
Nunca debe inicializar su variable a cero o nula en la primera pasada (cuando la está codificando por primera vez). Asignelo al valor real o no lo asigne en absoluto porque si no lo hace, Java puede decirle cuándo realmente lo arruinó. Tome la respuesta de Electric Monk como un gran ejemplo. En el primer caso, en realidad es increíblemente útil que te esté diciendo que si el try () falla porque el constructor de SomeObject arrojó una excepción, entonces terminarías con un NPE en el final. Si el constructor no puede lanzar una excepción, no debería estar en el intento.
Esta advertencia es un increíble verificador de programadores defectuosos de múltiples rutas que me ha salvado de hacer cosas estúpidas, ya que verifica cada ruta y se asegura de que si usó la variable en alguna ruta, entonces tuvo que inicializarla en cada ruta que conduzca a ella. . Ahora nunca inicializo explícitamente las variables hasta que determine que es lo correcto.
Además de eso, ¿no es mejor decir explícitamente "int size = 0" en lugar de "int size" y hacer que el próximo programador se dé cuenta de que su intención es que sea cero?
Por otro lado, no puedo encontrar una sola razón válida para que el compilador inicialice todas las variables no inicializadas a 0.
fuente
Creo que el propósito principal era mantener la similitud con C / C ++. Sin embargo, el compilador detecta y le advierte sobre el uso de variables no inicializadas que reducirán el problema a un punto mínimo. Desde la perspectiva del rendimiento, es un poco más rápido permitirle declarar variables no inicializadas, ya que el compilador no tendrá que escribir una declaración de asignación, incluso si sobrescribe el valor de la variable en la siguiente declaración.
fuente
(Puede parecer extraño publicar una nueva respuesta tanto tiempo después de la pregunta, pero surgió un duplicado ).
Para mí, la razón se reduce a esto: el propósito de las variables locales es diferente al propósito de las variables de instancia. Las variables locales se utilizan como parte de un cálculo; las variables de instancia están ahí para contener el estado. Si usa una variable local sin asignarle un valor, es casi seguro que se trata de un error lógico.
Dicho esto, podría atrasarme totalmente en exigir que las variables de instancia siempre se inicialicen explícitamente; el error ocurriría en cualquier constructor donde el resultado permita una variable de instancia no inicializada (por ejemplo, no inicializada en la declaración y no en el constructor). Pero esa no es la decisión de Gosling, et. al., tomó a principios de los 90, así que aquí estamos. (Y no estoy diciendo que hayan tomado la decisión incorrecta).
Sin embargo, no pude respaldar las variables locales predeterminadas. Sí, no deberíamos confiar en los compiladores para verificar nuestra lógica, y uno no lo hace, pero sigue siendo útil cuando el compilador detecta uno. :-)
fuente
Es más eficiente no inicializar variables y, en el caso de variables locales, es seguro hacerlo, porque el compilador puede rastrear la inicialización.
En los casos en los que necesite inicializar una variable, siempre puede hacerlo usted mismo, por lo que no es un problema.
fuente
La idea detrás de las variables locales es que solo existen dentro del ámbito limitado para el que son necesarias. Como tal, debería haber pocas razones para la incertidumbre en cuanto al valor, o al menos, de dónde proviene ese valor. Podría imaginar muchos errores derivados de tener un valor predeterminado para las variables locales.
Por ejemplo, considere el siguiente código simple ... ( NB, supongamos con fines de demostración que a las variables locales se les asigna un valor predeterminado, como se especifica, si no se inicializan explícitamente )
Cuando todo está dicho y hecho, asumiendo que el compilador asignó un valor predeterminado de '\ 0' a letterGrade , este código tal como está escrito funcionaría correctamente. Sin embargo, ¿qué pasa si olvidamos la declaración else?
Una ejecución de prueba de nuestro código puede resultar en lo siguiente
Este resultado, aunque era de esperar, seguramente no fue la intención del codificador. De hecho, probablemente en la gran mayoría de los casos (o al menos, en un número significativo de los mismos), el valor predeterminado no sería el valor deseado , por lo que en la gran mayoría de los casos el valor predeterminado resultaría en un error. Tiene más sentido forzar al codificador a asignar un valor inicial a una variable local antes de usarla, ya que el problema de depuración causado por olvidar el
= 1
infor(int i = 1; i < 10; i++)
supera con creces la conveniencia de no tener que incluir el= 0
infor(int i; i < 10; i++)
.Es cierto que los bloques try-catch-finalmente pueden volverse un poco desordenados (pero en realidad no es un catch-22 como parece sugerir la cita), cuando, por ejemplo, un objeto arroja una excepción marcada en su constructor, pero para uno razón u otra, se debe hacer algo con este objeto al final del bloque en finalmente. Un ejemplo perfecto de esto es cuando se trata de recursos, que deben cerrarse.
Una forma de manejar esto en el pasado podría ser así ...
Sin embargo, a partir de Java 7, este bloque finalmente ya no es necesario usando try-with-resources, como ese.
Dicho esto, (como sugiere el nombre) esto solo funciona con recursos.
Y aunque el ejemplo anterior es un poco asqueroso, esto quizás se refiera más a la forma en que se implementan try-catch-finalmente o estas clases que a las variables locales y cómo se implementan.
Es cierto que los campos se inicializan con un valor predeterminado, pero esto es un poco diferente. Cuando dice, por ejemplo,
int[] arr = new int[10];
tan pronto como haya inicializado esta matriz, el objeto existe en la memoria en una ubicación determinada. Supongamos por un momento que no hay valores predeterminados, sino que el valor inicial es cualquier serie de 1 y 0 que esté en esa ubicación de memoria en ese momento. Esto podría llevar a un comportamiento no determinista en varios casos.Supongamos que tenemos ...
Sería perfectamente posible que
Same.
se mostrara en una ejecución yNot same.
se mostrara en otra. El problema podría volverse aún más grave una vez que comience a hablar de variables de referencia.Según la definición, cada elemento de s debe apuntar a una cadena (o es nulo). Sin embargo, si el valor inicial es cualquier serie de 0 y 1 que ocurra en esta ubicación de memoria, no solo no hay garantía de que obtendrá los mismos resultados cada vez, sino que tampoco hay garantía de que el objeto s [0] apunte a (asumiendo que apunta a algo significativo) incluso es una Cadena (quizás sea un Conejo,: p )! Esta falta de preocupación por el tipo iría en contra de casi todo lo que hace Java Java. Entonces, si bien tener valores predeterminados para las variables locales podría verse como opcional en el mejor de los casos, tener valores predeterminados para las variables de ejemplo está más cerca de una necesidad .
fuente
si no me equivoco, otra razón podría ser
Dar el valor predeterminado de las variables miembro es parte de la carga de clases
La carga de clases es una cosa en tiempo de ejecución en Java, lo que significa que cuando crea un objeto, la clase se carga con la carga de clases, solo las variables miembro se inicializan con el valor predeterminado JVM no toma tiempo para dar un valor predeterminado a sus variables locales porque algunos métodos nunca serán llamado porque la llamada al método puede ser condicional, entonces, ¿por qué tomarse el tiempo para darles un valor predeterminado y reducir el rendimiento si esos valores predeterminados nunca se van a utilizar?
fuente
Eclipse incluso le da advertencias de variables no inicializadas, por lo que se vuelve bastante obvio de todos modos. Personalmente, creo que es bueno que este sea el comportamiento predeterminado; de lo contrario, su aplicación puede usar valores inesperados y, en lugar de que el compilador arroje un error, no hará nada (pero tal vez dará una advertencia) y luego estará rascando su cabeza en cuanto a por qué ciertas cosas no se comportan como deberían.
fuente
Las variables locales se almacenan en una pila, pero las variables de instancia se almacenan en el montón, por lo que hay algunas posibilidades de que se lea un valor anterior en la pila en lugar de un valor predeterminado como sucede en el montón. Por esa razón, jvm no permite usar una variable local sin inicializarla.
fuente
La variable de instancia tendrá valores predeterminados, pero las variables locales no pueden tener valores predeterminados. Dado que las variables locales están básicamente en métodos / comportamiento, su objetivo principal es realizar algunas operaciones o cálculos. Por lo tanto, no es una buena idea establecer valores predeterminados para las variables locales. De lo contrario, es muy difícil y requiere mucho tiempo verificar las razones de las respuestas inesperadas.
fuente
La respuesta es que las variables de instancia se pueden inicializar en el constructor de la clase o en cualquier método de la clase, pero en el caso de las variables locales, una vez que haya definido lo que sea en el método, permanecerá para siempre en la clase.
fuente
Podría pensar en seguir 2 razones
fuente