DEV Community

Java Efetivo (livro)
Java Efetivo (livro)

Posted on

Item 76: Empenhe-se para obter a atomicidade de falha

Definição

  • Um objeto deve permanecer em um estado utilizável e bem definido mesmo após lançar uma exceção durante uma operação.
  • Métodos que garantem que o objeto não será alterado após uma falha possuem atomicidade de falha.

Métodos para obter atomicidade de falha

Objetos Imutáveis

  • A atomicidade é inerente a objetos imutáveis porque seu estado não pode ser alterado após a criação.

Exemplo:

// Exemplo simplificado de um objeto imutável
public final class ImmutableObject {
    private final int value;

    public ImmutableObject(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

Enter fullscreen mode Exit fullscreen mode

Validação de Parâmetros Antes da Operação

  • Verificar a validade dos parâmetros antes de modificar o objeto.

Exemplo:

// Verificação de estado em um método Stack.pop()
public Object pop() {
    if (size == 0) {
        throw new IllegalStateException("Stack is empty");
    }
    Object result = elements[--size];
    elements[size] = null; // Evitar vazamento de memória
    return result;
}

Enter fullscreen mode Exit fullscreen mode

Ordenação de Operações

  • Garantir que partes passíveis de falha ocorram antes de alterar o estado do objeto.

Exemplo:

// Adicionando elemento em TreeMap (simulação)
public void addElement(TreeMap<String, Integer> map, String key, Integer value) {
    if (key == null || value == null) {
        throw new IllegalArgumentException("Key or value is null");
    }
    map.put(key, value); // Falhas na comparação ocorrem antes de alterar a estrutura
}

Enter fullscreen mode Exit fullscreen mode

Cópias Temporárias

  • Realizar operações em uma cópia temporária do objeto e substituir o original somente se a operação for bem-sucedida.

Exemplo:

// Simulação de operação em cópia temporária
public void sortList(List<Integer> list) {
    List<Integer> temp = new ArrayList<>(list);
    try {
        Collections.sort(temp);
        list.clear();
        list.addAll(temp);
    } catch (Exception e) {
        // A lista original permanece intacta
    }
}

Enter fullscreen mode Exit fullscreen mode

Código de Recuperação

  • Reverter o estado de um objeto ao original em caso de falha.
  • Geralmente usado em estruturas de dados persistentes.

Exemplo:

public void updateRecord(Database db, Record record) {
    Record backup = db.getRecord(record.getId()); // Fazer backup
    try {
        db.update(record);
    } catch (Exception e) {
        db.update(backup); // Reverter em caso de falha
    }
}

Enter fullscreen mode Exit fullscreen mode

Exceções Notáveis

  • Erros irreparáveis como ConcurrentModificationException ou AssertionError:
  • A atomicidade de falha não é garantida e nem necessária.

Custo e Complexidade

  • Nem sempre é prático implementar a atomicidade de falha, especialmente em operações complexas ou de alto custo.

Boa Prática

  • Métodos devem documentar o estado do objeto após uma falha se não garantirem atomicidade.

Resumo Final

  • Recomendação: Toda exceção que faça parte da especificação de um método deve deixar o objeto no mesmo estado anterior à invocação.
  • Exceções: Quando isso não for possível ou prático, a documentação da API deve ser clara sobre os impactos no estado do objeto.

Image description

Top comments (0)