2011-01-13 14 views
5

Personalmente, me gustan mucho los inicializadores de instancias, los uso para asignar valores predeterminados a cosas como colecciones, así que al escribir constructores no tengo que recordar asignarles los mismos valores predeterminados cada vez. Me parece bastante elegante: evita molestos aparejos de NPE y evita el código duplicado. Un método privado no parece tan bueno porque a) no puede asignar valores a los campos finales, b) podría ejecutarse en otro lugar en el código yc) el método aún necesita ser llamado explícitamente al inicio de cada constructor.¿Se consideran los inicializadores de instancias un estilo incorrecto?

Sin embargo, la otra cara de la moneda con la que he hablado es que son confusas, algunas personas que leen el código pueden no entender lo que hacen o cuándo se llaman y pueden causar más problemas de los que resuelven.

¿Se debe fomentar o evitar el uso correcto de estos inicializadores? ¿O es un caso "cada uno para ellos"?

+3

Ninguna función de idioma es "buena" o "mala" - todo tiene una situación en la que realmente brilla. Creo que una mejor pregunta es "¿en qué situaciones se deben evitar o usar los inicializadores de instancias?" – templatetypedef

+1

Casi siempre quiere que los campos de los tipos de colección sean 'finales', lo que soluciona el problema de NPE para esos. –

Respuesta

3

Depende, por ejemplo, del nivel de conocimiento sobre los lectores de Java que se espera que tenga el código y si las alternativas son prácticas.

Las alternativas son:

  • en línea en cada constructor. Si hay varios constructores, esto viola DRY.
  • tienen todos los delegados de constructores al mismo constructor, y ponen el código en ese.Si los constructores no son triviales y toman diferentes argumentos, puede ser necesario escribir un nuevo constructor que reciba los valores de todos los campos en sus argumentos. Si hay muchos campos, esto puede ser bastante largo (y difícil de leer, ya que no es obvio qué valor se le asigna a qué campo)
  • tienen todos los constructores invocan un método init. No se pueden asignar campos finales de esa manera. Probablemente debería evitar que el método sea anulado. Es posible que desee evitar que se llame varias veces.

Dado que los inicializadores son poco comunes, solo debería preferirlos cuando haya una clara ventaja de su uso. Mi uso más reciente de una era:

private final Collator collator = Collator.getInstance(); 
{ 
    collator.setStrength(Collator.SECONDARY); 
} 

en una clase con varios constructores con bastante diferentes listas de argumentos y media docena de otros campos.

0

Puede usar un constructor con parámetros y este constructor llama a los establecedores privados. Y que implemente un constructor predeterminado que llame a ese contructor con valores predeterminados. Si desea asignar valores predeterminados a las propiedades, hágalo en la declaración.

La instancia y los inicializadores estáticos son buenos para iniciar estructuras de datos complejas como matrices o cubos.

Por cierto, una propiedad final se llama principalmente una constante.

+2

Setters privados? ¿Cuál sería el objetivo de eso? En segundo lugar, un constructor predeterminado generalmente no debe llamar a otro constructor dentro de la misma clase. Por último, las propiedades "finales" no son "constantes" en el sentido tradicional. No se pueden cambiar una vez configurados, pero cada instancia puede tener su propio valor no modificable establecido en el tiempo de ejecución. En el mundo de Java, una "constante" generalmente significa "final estática" y generalmente se establece en tiempo de diseño. –

1

Realmente no los uso, pero un caso que los veo útiles es cuando tienes varios constructores, que no se llaman a sí mismos (esto (..)), que necesitan una lógica de inicialización común compartida, y no es necesario crear un método privado específico para eso. Ah, y el único lugar que utilizan inicializadores de instancia son para inicializar rápidamente en una línea Mapas por ejemplo, por ejemplo:

Map<String,String> m = new HashMap<String,String>(){{ 
    put("a","b"); 
    put("c","b"); 
    put("d","b"); 
}}; 

podría ser útil para inicializar un mapa en digamos una interfaz

interface A { 

    Map<String,String> PROPS = Collections.unmodifiableMap(new HashMap<String,String>(){{ 
     put("a","b"); 
     put("c","b"); 
     put("d","b"); 
    }}); 
} 

Aún así, termina con una subclase anónima de HashMap ...

1

Es mejor sobrecargar su constructor y tener tantas variaciones de constructor como desee. El mejor ejemplo es el Arraylist de Java. Tiene dos constructores. Uno que toma un entero como argumento y otro es un constructor predeterminado. Si se echa un vistazo en el constructor por defecto, que de hecho llama al constructor argumento individual con un valor constante 10.

List<Object> x = new ArrayList<Object>(); //Creates with default capacity 10 
List<Object> y = new ArrayList<Object>(40); //Creates with the specified capacity 40 
1

Me alojaría son los preferidos. Pero según las otras respuestas, parece que podría ser más "para cada uno". Me gustan porque mantiene la información relacionada en conjunto. En lugar de declarar un valor y configurarlo en el constructor, puede hacerlo todo en un solo lugar.

Cuestiones relacionadas