una - ¿Debo mantener las variables de instancia en Java siempre inicializadas o no?
que es un atributo en java (12)
Recientemente comencé un nuevo proyecto y estoy tratando de mantener mis variables de instancia siempre inicializadas con algún valor, por lo que ninguna de ellas es en ningún momento nula. Pequeño ejemplo a continuación:
public class ItemManager {
ItemMaster itemMaster;
List<ItemComponentManager> components;
ItemManager() {
itemMaster = new ItemMaster();
components = new ArrayList<ItemComponentManager>();
}
...
}
El objetivo principal es evitar la tediosa comprobación de null antes de usar una variable de instancia en algún lugar del código. Hasta ahora, está funcionando bien y, en general, no necesita el valor nulo, ya que también puede verificar cadenas vacías o listas vacías, etc. No estoy utilizando este método para las variables con ámbito de método ya que su alcance es muy limitado y por eso no afecta otras partes del código.
Todo esto es algo experimental, por lo que me gustaría saber si este enfoque podría funcionar o si hay algunas dificultades que aún no veo. ¿Es generalmente una buena idea mantener las variables de instancia inicializadas?
El objetivo principal es evitar la tediosa comprobación de null antes de utilizar una variable de clase en algún lugar del código.
Aún debe verificar null. Las bibliotecas de terceros e incluso la API de Java algunas veces devolverán null.
Además, crear instancias de un objeto que nunca se puede utilizar es un desperdicio, pero eso dependería del diseño de su clase.
¿Qué sucede si en uno de tus métodos configuras
itemMaster = null;
o devuelve una referencia al ItemManager a alguna otra clase y establece itemMaster como nulo. (Puede protegerse contra esto devolviendo fácilmente un clon de su ItemManager, etc.)
Mantendré los cheques ya que esto es posible.
Desde el nombre de la clase "ItemManager", ItemManager suena como un singleton en alguna aplicación. Si es así, debes investigar y realmente, realmente, saber Dependency Injection. Use algo como Spring ( http://www.springsource.org/ ) para crear e insertar la lista de ItemComponentManagers en ItemManager.
Sin DI, la inicialización manual de aplicaciones serias es una pesadilla para depurar y conectar varias clases de "gerentes" para hacer pruebas limitadas es un infierno.
Use DI siempre (incluso al construir pruebas). Para los objetos de datos, cree un método get () que cree la lista si no existe. Sin embargo, si el objeto es complejo, seguramente encontrará su vida mejor utilizando el patrón Fábrica o Constructor y hará que el F / B establezca las variables miembro según sea necesario.
En primer lugar, todas las variables de instancia no finales deben declararse privadas si desea conservar el control.
También considere la instanciación lenta: esto también evita el "mal estado", pero solo se inicializa con el uso:
class Foo {
private List<X> stuff;
public void add(X x) {
if (stuff == null)
stuff = new ArrayList<X>();
stuff.add(x);
}
public List<X> getStuff() {
if (stuff == null)
return Collections.emptyList();
return Collections.unmodifiableList(stuff);
}
}
(Tenga en cuenta el uso de Collections.unmodifiableList - a menos que realmente desee que una persona que llama pueda agregar / eliminar de su lista, debe hacerlo inmutable)
Piense en cuántas instancias del objeto en cuestión se crearán. Si hay muchos, y siempre crea las listas (y podría terminar con muchas listas vacías), podría estar creando muchos más objetos de los que necesita.
Aparte de eso, es realmente una cuestión de gusto y si puedes tener valores significativos cuando construyes.
Si estás trabajando con un DI / IOC, quieres que el framework haga el trabajo por ti (aunque puedes hacerlo a través de la inyección de constructor, prefiero setters) - Scott
He encontrado algunos casos donde esto causa problemas. Durante la deserialización, algunos frameworks no llaman al constructor, no sé cómo o por qué eligen hacerlo, pero sucede. Esto puede provocar que sus valores sean null
. También he encontrado el caso donde se llama al constructor, pero por alguna razón las variables miembro no se inicializan.
De hecho, usaría el siguiente código en lugar del suyo:
public class ItemManager {
ItemMaster itemMaster = new ItemMaster();
List<ItemComponentManager> components = new ArrayList<ItemComponentManager>();
ItemManager() {
...
}
...
}
La forma en que trato con cualquier variable que declaro es decidir si cambiará a lo largo de la vida del objeto (o clase si es estática). Si la respuesta es "no", la hago definitiva.
Hacerlo definitivo te obliga a darle un valor cuando se crea el objeto ... personalmente yo haría lo siguiente a menos que supiera que cambiaría el objetivo:
private final ItemMaster itemMaster; private final List components; // instance initialization block - happens at construction time { itemMaster = new ItemMaster(); components = new ArrayList(); }
Tal como está ahora su código, debe verificar nulo todo el tiempo porque no marcó las variables como privadas (lo que significa que cualquier clase en el mismo paquete puede cambiar los valores a nulo).
Los haría finales si es posible. Luego deben inicializarse en el constructor y no pueden ser nulos.
También debe hacerlos privados en cualquier caso, para evitar que otras clases les asignen nulos. Si puede verificar que null nunca se asigna en su clase, entonces el enfoque funcionará.
Normalmente trato una colección vacía y una colección nula como dos cosas separadas:
Una colección vacía implica que sé que hay cero elementos disponibles. Una colección nula me dirá que no sé el estado de la colección, que es algo diferente.
Así que realmente no creo que sea una de las dos cosas. Y declararía la variable final si los inicializo en el constructor. Si declara que es definitiva, queda claro para el lector que esta colección no puede ser nula.
Sí, es una muy buena idea inicializar todas las variables de clase en el constructor.
Si es todo tu código y quieres establecer esa convención, debería ser algo bueno tener. Estoy de acuerdo con el comentario de Paul, sin embargo, que nada impide que un código erróneo accidentalmente establezca una de las variables de su clase como nula. Como regla general, siempre compruebo null. Sí, es un PITA, pero la codificación defensiva puede ser algo bueno.
Un objeto debe estar 100% listo para usar después de su construcción. Los usuarios no deberían tener que comprobar nulos. La programación defensiva es el camino a seguir, mantenga los controles.
En interés de DRY, puede colocar los cheques en los incubadores y simplemente hacer que el constructor los llame. De esta forma, no codifica los cheques dos veces.
Yo diría que está totalmente bien, siempre y cuando recuerde que tiene valores de marcador de posición "vacíos" allí y no datos reales.
Mantenerlos nulos tiene la ventaja de obligarlo a tratar con ellos; de lo contrario, el programa se bloquea. Si crea objetos vacíos, pero los olvida, obtiene resultados indefinidos.
Y solo para comentar sobre la codificación de defensa: si usted es el que crea los objetos y nunca los establece nulos, no hay necesidad de buscar nulos cada vez. Si por algún motivo obtiene un valor nulo, entonces sabrá que algo ha fallado catastróficamente y que el programa se bloqueará de todos modos.