DEV Community

Java Efetivo (livro)
Java Efetivo (livro)

Posted on

Item 83: Utilize a inicialização preguiçosa com parcimônia

O que é inicialização preguiçosa?

  • Definição: Adiar a inicialização de um campo até que ele seja acessado pela primeira vez.
  • Benefícios: Evita inicializações desnecessárias se o campo nunca for usado.
  • Aplicações: Usada para campos estáticos e de instância.

Práticas Recomendadas e Exemplos

  1. Inicialização Normal (Preferível) Simples e eficaz.

Exemplo:

private final FieldType field = computeFieldValue();

Enter fullscreen mode Exit fullscreen mode

Use inicialização normal para a maioria dos campos, salvo necessidade especial.

  1. Inicialização Preguiçosa com Getter Sincronizado Quando usar: Para resolver circularidades de inicialização.

Exemplo:

private FieldType field;

synchronized FieldType getField() {
    if (field == null) {
        field = computeFieldValue();
    }
    return field;
}

Enter fullscreen mode Exit fullscreen mode

3. Prática da Classe Portadora (Para Campos Estáticos)

  • Quando usar: Inicialização preguiçosa eficiente para campos estáticos.

Exemplo:

private static class FieldHolder {
    static final FieldType field = computeFieldValue();
}

static FieldType getField() {
    return FieldHolder.field;
}

Enter fullscreen mode Exit fullscreen mode

Vantagem: Inicializa a classe apenas quando o campo é acessado, com custo mínimo após a inicialização.

4. Prática de Verificação Dupla (Para Campos de Instância)

  • Quando usar: Para desempenho em inicialização preguiçosa em campos de instância.

Exemplo:

private volatile FieldType field;

FieldType getField() {
    FieldType result = field;
    if (result == null) { // Primeira verificação (sem bloqueio)
        synchronized (this) {
            result = field;
            if (result == null) { // Segunda verificação (com bloqueio)
                field = result = computeFieldValue();
            }
        }
    }
    return result;
}

Enter fullscreen mode Exit fullscreen mode

5. Prática de Verificação Única (Inicialização Repetida Permitida)

  • Quando usar: Campos que podem tolerar inicializações repetidas.

Exemplo

private volatile FieldType field;

FieldType getField() {
    if (field == null) { // Verificação única
        field = computeFieldValue();
    }
    return field;
}

Enter fullscreen mode Exit fullscreen mode

6. Prática Ousada de Verificação Única

  • Quando usar: Apenas se tolerar inicializações extras e se o tipo do campo for um primitivo diferente de long ou double.

Exemplo:

private FieldType field;

FieldType getField() {
    if (field == null) { // Sem volatile
        field = computeFieldValue();
    }
    return field;
}

Enter fullscreen mode Exit fullscreen mode

Considerações Gerais

Trade-offs:

  • Inicialização preguiçosa minimiza o custo inicial, mas pode aumentar o custo de acesso ao campo.
  • Avalie com medições de desempenho.

Sincronização em Multithread:

  • Fundamental para evitar bugs graves.
  • Utilize práticas seguras (e.g., volatile, bloqueios).

Uso Preferencial:

  • Campos Estáticos: Prática da classe portadora.
  • Campos de Instância: Verificação dupla.
  • Inicialização Repetida Permitida: Verificação única.

Resumo Final

  • Inicialize normalmente sempre que possível.
  • Use inicialização preguiçosa apenas quando necessário para desempenho ou para resolver problemas de circularidade

Top comments (0)