Java: Quando um bloco de inicialização estática é útil?

96

Qual é a diferença entre a inicialização dentro de um staticbloco:

public class staticTest {

    static String s;
    static int n;
    static double d;

    static {
        s = "I'm static";
        n = 500;
        d = 4000.0001;
    }
    ...

E inicialização estática individual:

public class staticTest {

    static String s = "I'm static";
    static int n    = 500;
    static double d = 4000.0001;

    ....
Adam Matan
fonte
1
Você só está usando atribuições no bloco de inicialização estática, então é claro que isso pode ser feito usando atribuição de variável estática. Você já tentou ver o que acontece se você precisar executar instruções sem atribuição?
Platinum Azure de
É um bom lugar para carregar classes ou biblioteca nativa.
qrtt1
1
Observe que as variáveis ​​estáticas devem ser evitadas e, portanto, os blocos de inicialização estáticos geralmente não são uma boa ideia. Se você os usa muito, espere alguns problemas no futuro.
Bill K,

Respostas:

113

Um bloco de inicialização estático permite uma inicialização mais complexa, por exemplo, usando condicionais:

static double a;
static {
    if (SomeCondition) {
      a = 0;
    } else {
      a = 1;
    }
}

Ou quando mais do que apenas construção é necessária: ao usar um construtor para criar sua instância, o tratamento de exceções ou trabalho diferente de criar campos estáticos é necessário.

Um bloco de inicialização estática também é executado após os inicializadores estáticos in-line, portanto, o seguinte é válido:

static double a;
static double b = 1;

static {
    a = b * 4; // Evaluates to 4
}
Rich O'Kelly
fonte
3
Fazendo "b = a * 4;" inline só seria um problema se b fosse declarado antes de a, o que não é o caso em seu exemplo.
George Hawkins
1
@GeorgeHawkins Eu estava apenas tentando ilustrar que um inicializador estático é executado após inicializadores embutidos, não que um equivalente não possa ser feito embutido. No entanto, entendi seu ponto e atualizei o exemplo para (espero) ser mais claro.
Rich O'Kelly
1
Apenas por diversão, posso apontar que seu primeiro exemplo poderia ser facilmente "static double a = someCondition? 0: 1;" Não que seus exemplos não sejam bons, só estou dizendo ... :)
Bill K
18

Um uso típico:

private final static Set<String> SET = new HashSet<String>();

static {
    SET.add("value1");
    SET.add("value2");
    SET.add("value3");
}

Como você faria isso sem o inicializador estático?

gawi
fonte
2
Resposta: Goiaba :) +1
Paul Bellora
2
Outra resposta sem bibliotecas adicionais: crie um método estático que encapsule a inicialização SETe use a variável initializer ( private final static Set<String> SET = createValueSet()). E se você tivesse 5 conjuntos e 2 mapas, você simplesmente despejaria todos eles em um único staticbloco?
TWiStErRob
16

Você pode usar o bloco try / catch dentro static{}como abaixo:

MyCode{

    static Scanner input = new Scanner(System.in);
    static boolean flag = true;
    static int B = input.nextInt();
    static int H = input.nextInt();

    static{
        try{
            if(B <= 0 || H <= 0){
                flag = false;
                throw new Exception("Breadth and height must be positive");
            }
        }catch(Exception e){
            System.out.println(e);
        }

    }
}

PS: Referido a partir disso !

Karan Patel
fonte
12

O tratamento de exceções durante a inicialização é outro motivo. Por exemplo:

static URL url;
static {
    try {
        url = new URL("https://blahblah.com");
    }
    catch (MalformedURLException mue) {
        //log exception or handle otherwise
    }
}

Isso é útil para construtores que irritantemente lançam exceções verificadas, como acima, ou então uma lógica de inicialização mais complexa que pode ser sujeita a exceções.

Paul Bellora
fonte
5

Às vezes, você deseja fazer mais do que apenas atribuir valores a variáveis ​​estáticas. Visto que você não pode colocar instruções arbitrárias no corpo da classe, você poderia usar um bloco inicializador estático.

Jesper
fonte
4

No seu exemplo, não há diferença; mas muitas vezes o valor inicial é mais complexo do que confortavelmente expresso em uma única expressão (por exemplo, é um List<String>cujo conteúdo é melhor expresso por um for-loop; ou é um Methodque pode não existir, portanto, manipuladores de exceção são necessários) e / ou os campos estáticos precisam ser definidos em uma ordem específica.

Ruakh
fonte
4

staticbloco pode ser usado para inicializar a instância singleton , para evitar o uso do método sincronizado getInstance() .

Marinheiro danubiano
fonte
3

Tecnicamente, você poderia escapar sem ele. Alguns preferem que o código de inicialização de várias linhas entre em um método estático. Estou muito feliz em usar um inicializador estático para uma inicialização de várias instruções relativamente simples.

Claro, eu quase sempre faria minha estática finale apontaria para um objeto não modificável.

Tom Hawtin - tackline
fonte
3

A palavra-chave estática (seja uma variável ou bloco) pertence à classe. Portanto, quando a classe é chamada, essas variáveis ​​ou blocos são executados. Portanto, a maior parte da inicialização será feita com a ajuda da palavra-chave estática. Por pertencer à própria classe, a classe pode acessá-la diretamente, sem criar uma instância da classe.

Vamos dar um exemplo, há uma classe de calçados em que existem várias variáveis ​​como cor, tamanho, marca etc ... E aqui se a empresa fabricante de calçados tem apenas uma marca, devemos inicializá-la como uma variável estática. Portanto, quando a classe de calçados é chamada e diferentes tipos de calçados são fabricados (criando uma instância da classe), naquele momento, a cor e o tamanho ocuparão a memória sempre que um novo calçado for criado, mas aqui a marca é uma propriedade comum para todos os calçados, de modo que ocupará a memória uma vez, não importa quantos sapatos sejam fabricados.

Exemplo:

    class Shoe {
    int size;
    String colour;
    static String brand = "Nike";

    public Shoe(int size, String colour) {
        super();
        this.size = size;
        this.colour = colour;
    }

    void displayShoe() {
        System.out.printf("%-2d %-8s %s %n",size,colour, brand);
    }

    public static void main(String args[]) {
        Shoe s1 = new Shoe(7, "Blue");
        Shoe s2 = new Shoe(8, "White");

        System.out.println("=================");
        s1.displayShoe();
        s2.displayShoe();
        System.out.println("=================");
    }
}
imbuir
fonte
1

O bloco de código estático permite inicializar os campos com mais de uma instrução, inicializar os campos em uma ordem diferente das declarações e também pode ser usado para a inicialização condicional.

Mais especificamente,

static final String ab = a+b;
static final String a = "Hello,";
static final String b = ", world";

não funcionará porque aeb são declarados após ab.

No entanto, eu poderia usar um init estático. bloco para superar isso.

static final String ab;
static final String a;
static final String b;

static {
  b = ", world";
  a = "Hello";
  ab = a + b;
}

static final String ab;
static final String a;
static final String b;

static {
  b = (...) ? ", world" : ", universe";
  a = "Hello";
  ab = a + b;
}
algolicious
fonte
3
Embora o que você está dizendo seja verdade, isso não demonstra a necessidade de um bloco inicializador estático. Você pode simplesmente mover sua abdeclaração abaixo da declaração de b.
gawi de
1

Usamos construtores para inicializar nossas variáveis ​​de instância (variáveis ​​não estáticas, variáveis ​​que pertencem a objetos, não a classe).

Se você deseja inicializar variáveis ​​de classe (variáveis ​​estáticas) e deseja fazê-lo sem criar um objeto (construtores só podem ser chamados ao criar um objeto), então você precisa de blocos estáticos.

static Scanner input = new Scanner(System.in);
static int widht;
static int height;

static
{
    widht = input.nextInt();
    input.nextLine();
    height = input.nextInt();
    input.close();

    if ((widht < 0) || (height < 0))
    {
        System.out.println("java.lang.Exception: Width and height must be positive");
    }
    else
    {
        System.out.println("widht * height = " + widht * height);
    }
}
Michael
fonte
Ler stdin em um inicializador estático é uma ideia horrível. E System.out.println("B * H");é bastante inútil. E a resposta em si é muito vaga. OP não mencionou construtores ou variáveis ​​de instância.
shmosel
Este é apenas um exemplo que mostra o que é um inicializador estático e como ele é usado. OP não pediu construtores ou variáveis ​​de instância, mas para ensiná-lo a diferença entre o inicializador estático e o construtor, ele precisa saber disso. Do contrário, ele diria "Por que não uso apenas um construtor para inicializar minhas variáveis ​​estáticas?"
Michael,
0

Um bloco de inicialização estático é útil se você deseja inicializar os tipos estáticos de classe especificados, antes do primeiro uso da classe. O uso subsequente não invocará nenhum bloco de inicialização estático. É o oposto direto de inicializadores de instância, que inicializam membros de instância.

Remario
fonte
0

Quando você quiser avaliar qualquer expressão durante o tempo de carregamento da classe, você pode usar o bloco estático, mas lembre-se:

Você deve tratar uma exceção no bloco estático, o que significa que você não pode lançar uma exceção de um bloco estático.

I'm_Pratik
fonte