Por que os inicializadores de instância do Java?

Qual é o sentido de “Inicializadores de instâncias” em Java?
Não podemos simplesmente colocar esse bloco de código no começo do construtor?

Eu os uso com muita frequência, normalmente para criar e preencher o Map em uma declaração (em vez de usar um bloco estático feio):

private static final Map CODES = new HashMap() { { put("A", "Alpha"); put("B", "Bravo"); } }; 

Um embelezamento interessante e útil para isso é criar um mapa não modificável em uma declaração:

 private static final Map CODES = Collections.unmodifiableMap(new HashMap() { { put("A", "Alpha"); put("B", "Bravo"); } }); 

É mais simples do que usar blocos estáticos e lidar com atribuições singulares para final etc.

E outra dica: não tenha medo de criar methods que simplifiquem seu bloco de instâncias:

 private static final Map CODES = new HashMap() { { put("Alpha"); put("Bravo"); } void put(String code) { put(code.substring(0, 1), code); } }; 

Você poderia, de fato, colocar o código no começo de cada construtor. No entanto, esse é precisamente o ponto de um inicializador de instância: seu código é aplicado a todos os construtores, o que pode ser útil se você tiver muitos construtores e um pouco de código que seja comum a todos eles.

(Se você está apenas começando com a programação, você pode não saber que é possível criar muitos construtores para a mesma class (desde que eles tenham parâmetros diferentes), isso é conhecido como sobrecarga de construtor . construtor, então um inicializador de instância não é realmente muito útil (Edit: a menos que você abuse de moda criativa, como ilustrado nas outras respostas).)

Você pode usar o inicializador de instância ao declarar uma class anônima, por exemplo, ao perpetrar o Idioma de Inicialização de Chave Dupla .

 List mylist = new ArrayList(){{add("a"); add("b"); add("c");}}; 

Aqui você pode inicializar o object mesmo que você não possa adicionar nada ao construtor (porque a class é anônima).

Como todos os exemplos de código aqui usam classs anônimas, eu juntei essa class (um pouco horrível) que demonstra o uso de inicializadores de instância em uma class “apropriada”. Você pode usá-los para fazer processamento complexo ou manipular exceções no momento da boot. Observe que esses blocos são executados antes que o construtor seja executado, mas o construtor é executado antes que os inicializadores em uma class filha sejam executados:

 import java.util.Scanner; public class InstanceInitializer { int x; { try { System.out.print("Enter a number: "); x = Integer.parseInt(new Scanner(System.in).nextLine()); } catch (NumberFormatException e) { x = 0; } } String y; { System.out.print("Enter a string: "); y = new Scanner(System.in).nextLine(); for(int i = 0; i < 3; i++) y += y; } public InstanceInitializer() { System.out.println("The value of x is "+x); System.out.println("The value of y is "+y); } public static class ChildInstanceInitializer extends InstanceInitializer { { y = "a new value set by the child AFTER construction"; } } public static void main(String[] args){ new InstanceInitializer(); new InstanceInitializer(); System.out.println(); System.out.println(new ChildInstanceInitializer().y); // This is essentially the same as: System.out.println(new InstanceInitializer(){ {y = "a new value set by the child AFTER construction";} }.y); } } 

Esta saída (algo como):

 Enter a number: 1 Enter a string: a The value of x is 1 The value of y is aaaaaaaa Enter a number: q Enter a string: r The value of x is 0 The value of y is rrrrrrrr Enter a number: 3 Enter a string: b The value of x is 3 The value of y is bbbbbbbb a new value set by the child AFTER construction Enter a number: s Enter a string: Hello The value of x is 0 The value of y is HelloHelloHelloHelloHelloHelloHelloHello a new value set by the child AFTER construction 

Observe que a string "new value" não é definida até que o construtor da class pai já tenha sido chamado.