Exceções e arquivos em Java

Aprenda como Java informa problemas durante a execução de um programa e como lidar com eles. Interprete rastreamentos da pilha, distinga exceções verificadas de não verificadas e trate erros com try, catch e finally. Lance suas próprias exceções e projete classes de exceção que informem exatamente o que deu errado. Depois, leia e grave arquivos de texto controlando caminhos, codificações e terminadores de linha, feche cada arquivo com segurança usando try-with-resources e desenvolva um programa que lide com arquivos ausentes e dados inválidos.

BásicoAula 9 de 11 do curso Curso de Programação orientada a objetos com Java

O que você vai aprender

  1. Reconheça uma exceção quando um programa falhar, interprete o rastreamento da pilha para descobrir onde e por que ela ocorreu e situe qualquer exceção na hierarquia de classes de Java como verificada ou não verificada.
    • Interprete uma exceção e seu rastreamento da pilha
      Explique o que acontece quando uma instrução lança uma exceção, nomeie as exceções de execução comuns e suas causas e use um rastreamento da pilha para localizar o problema.
    • Classifique exceções como verificadas ou não verificadas
      Situe qualquer exceção na hierarquia abaixo de Throwable, determine se ela é verificada ou não verificada e aplique a regra de que exceções verificadas devem ser capturadas ou declaradas.
  2. Capture as exceções que um programa pode esperar, recupere a execução de forma adequada, trate vários tipos na ordem correta e execute o código de limpeza independentemente do que acontecer.
    • Capture uma exceção e recupere a execução
      Escreva uma instrução try-catch, acompanhe o fluxo de controle por ela e recupere a execução após uma entrada inválida em vez de deixar o programa falhar.
    • Trate vários tipos de exceção na ordem correta
      Use várias cláusulas catch ou uma captura múltipla, ordene-as da mais específica para a mais geral e decida onde um bloco try deve começar e terminar.
    • Execute código de limpeza com finally
      Adicione um bloco finally, acompanhe quando ele é executado em cada caminho de uma instrução try e evite erros que façam finally ocultar problemas.
  3. Sinalize problemas em seus próprios métodos com throw, declare exceções verificadas com throws e crie classes de exceção que informem aos chamadores exatamente o que deu errado.
    • Lance exceções e declare-as com throws
      Valide argumentos e o estado de objetos lançando exceções padrão, declare exceções verificadas em cabeçalhos de métodos e decida onde uma exceção deve ser tratada.
    • Crie classes de exceção personalizadas e preserve a causa
      Escreva suas próprias classes de exceção verificadas ou não verificadas, lance-as antes de alterar o estado de um objeto e encapsule uma exceção de baixo nível sem perdê-la.
  4. Indique ao programa o arquivo correto, compreenda como o texto é armazenado como bytes e linhas e garanta que todo arquivo aberto seja fechado com try-with-resources.
    • Trabalhe com caminhos, codificações e terminadores de linha
      Construa caminhos para arquivos, preveja onde Java procura um caminho relativo e explique como codificações de caracteres, terminadores de linha e formatos numéricos afetam arquivos de texto.
    • Feche recursos automaticamente com try-with-resources
      Use try-with-resources para abrir e fechar arquivos e outros recursos, preveja a ordem de fechamento e explique como ele impede a perda de exceções.
  5. Leia arquivos de texto linha por linha e transforme suas linhas em dados, grave resultados em arquivos ou acrescente-os ao final e combine tudo em um programa que lide com arquivos ausentes e registros inválidos.
    • Leia um arquivo de texto e transforme suas linhas em dados
      Leia um arquivo com Scanner, Files.readAllLines ou BufferedReader, divida e converta cada linha e ignore ou informe linhas que não correspondam ao formato esperado.
    • Grave arquivos de texto e acrescente conteúdo ao final
      Grave texto em um arquivo novo ou existente, acrescente conteúdo sem apagar o que já está lá e garanta que tudo o que for gravado realmente chegue ao arquivo.
    • Desenvolva um programa robusto de processamento de arquivos
      Combine leitura, análise e conversão, exceções e gravação em um programa que pare de forma controlada em falhas no processamento do arquivo inteiro, ignore e informe registros inválidos e evite saídas parciais.

Guia de estudo de Exceções em Java

5 capítulos

1

Compreenda o que são exceções e como Java as classifica

Um programa pode compilar com sucesso e ainda falhar ao receber um vetor vazio, texto inválido ou um arquivo ausente. O objeto de exceção e seu rastreamento da pilha fornecem evidências sobre essa falha. Acompanhe o rastreamento pelas chamadas de método ativas e use a hierarquia de classes para decidir se Java exige uma decisão de tratamento em tempo de compilação. Isso prepara você para distinguir defeitos a corrigir de problemas esperados dos quais seu programa pode se recuperar.

1.1 Encontre a instrução que falhou

Uma exceção é um objeto que descreve um problema que interrompe um programa em execução. Lançá-la interrompe a instrução atual. Java ignora o restante do trabalho normal até encontrar um tratador compatível; sem ele, a exceção passa de volta pelos métodos que o chamaram.

Reconheça o tipo de problema

A falta de um ponto e vírgula é um erro de compilação: o programa não consegue compilar. Uma exceção ocorre quando o código compilado é executado com dados que provocam um problema.

ExceçãoCausa típica
ArithmeticExceptionDivisão inteira por zero
ArrayIndexOutOfBoundsExceptiona[3] quando o vetor tem comprimento 3
IndexOutOfBoundsExceptionlist.get(list.size())
NullPointerExceptionChamada de um método por meio de null
NumberFormatExceptionInteger.parseInt("12a")
InputMismatchExceptionScanner.nextInt() encontra “dez”
ClassCastExceptionConversão de um objeto para uma classe à qual ele não pertence

Os índices de vetores começam em 0, então comprimento 3 significa índices válidos 0, 1 e 2. A divisão em ponto flutuante segue regras diferentes: 10.0 / 0 produz Infinity; ela não lança a exceção de divisão inteira.

Leia um rastreamento de cima para baixo

Aqui está uma classe completa, sem linhas em branco antes da primeira linha:

public class Average {
    static int average(int[] values) {
        int sum = 0;
        for (int value : values) sum += value;
        return sum / values.length;
    }
    public static void main(String[] args) {
        int[] values = new int[0];
        System.out.println(average(values));
    }
}

O vetor está vazio, portanto seu comprimento é 0. A divisão na linha 5 falha. O rastreamento é:

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at Average.average(Average.java:5)
    at Average.main(Average.java:9)
  1. Leia a primeira linha para identificar a classe e a mensagem da exceção.
  2. Leia o primeiro registro de ativação com at para identificar o ponto em que o problema foi detectado.
  3. Leia para baixo para encontrar os chamadores: main chamou average na linha 9.
  4. Se os primeiros registros pertencerem à biblioteca de Java, encontre o primeiro que menciona sua própria classe. Para uma chamada de Integer.parseInt que falhou, registros da biblioteca podem preceder a chamada em seu código.

O rastreamento segue a pilha de chamadas, a cadeia de chamadas de método ativas. Ele indica onde investigar, mas o valor inválido pode ter sido criado antes. Aqui a divisão detecta o problema; o chamador forneceu o vetor vazio. Decida se uma entrada vazia deve ser rejeitada ou tratada antes de calcular uma média.

Examine o objeto de exceção

e.getMessage() retorna a mensagem e pode retornar null. e.toString() inclui o nome da classe e, quando presente, a mensagem. e.printStackTrace() exibe o rastreamento no erro padrão. Uma seção Caused by: mostra uma exceção anterior preservada dentro de um encapsulador.

Mensagens de NullPointerException geradas pela JVM normalmente identificam a expressão nula. Uma exceção criada explicitamente pode ter uma mensagem personalizada ou nenhuma. Acompanhe a referência até o ponto em que ela deveria ter recebido um objeto.

Uma exceção sem tratamento que sai de main encerra a thread principal; isso encerra um programa com uma única thread. Corrija defeitos como índices incorretos no código. Planeje a recuperação para problemas externos esperados, como um arquivo ausente ou uma entrada inválida do usuário.

Principais conclusões

  • Uma exceção interrompe a execução normal; instruções ignoradas não são retomadas automaticamente.
  • Leia a classe e a mensagem da exceção e acompanhe os registros de ativação desde a falha detectada até seus chamadores.
  • Registros de ativação da biblioteca podem aparecer antes do primeiro registro em seu próprio código.
  • A instrução que falhou pode revelar um valor inválido criado anteriormente.
  • Corrija defeitos de programação e trate falhas esperadas de entrada ou de arquivos.

1.2 Exceções verificadas e não verificadas

As classes de exceção usam as regras de herança que você já conhece. Um objeto lançado de uma subclasse também pertence à sua superclasse, o que explica tanto as categorias de exceção de Java quanto a forma como um tratador corresponde a elas.

Acompanhe a hierarquia

Somente objetos de Throwable ou de suas subclasses podem ser lançados. Dois ramos principais estão abaixo dela:

Throwable
  Error
    OutOfMemoryError
    StackOverflowError
  Exception
    RuntimeException
      IllegalArgumentException
        NumberFormatException
      NullPointerException
      IndexOutOfBoundsException
        ArrayIndexOutOfBoundsException
    IOException
      FileNotFoundException
      NoSuchFileException

Error descreve falhas graves do ambiente de execução. Uma aplicação comum não deve tentar se recuperar de um heap esgotado ou de uma pilha esgotada por recursão infinita. Exception descreve problemas que uma aplicação pode tratar, incluindo seu ramo RuntimeException.

CategoriaClassesExigência do compilador
Não verificadaRuntimeException, Error e suas subclassesCapturar ou declarar é opcional
VerificadaTodas as outras subclasses de ThrowableCapturar ou declarar quando o código puder lançá-las

Ambos os tipos são lançados em tempo de execução. A palavra “verificada” descreve a verificação do tratamento pelo compilador, não um momento anterior em que a falha ocorre. Não verificada também não significa inofensiva: uma referência nula sem tratamento pode interromper um programa.

Aplique a regra de capturar ou declarar

A leitura de um arquivo pode falhar mesmo em código correto. Um método auxiliar pode deixar a decisão para seu chamador:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

class Names {
    static List<String> load(Path file) throws IOException {
        return Files.readAllLines(file);
    }
}

Files.readAllLines pode lançar a exceção verificada IOException. A declaração passa essa possibilidade ao chamador, que também deve capturá-la ou declará-la. Remover throws IOException sem adicionar um tratador faz o método auxiliar falhar na compilação. Um método que usa Integer.parseInt não tem uma obrigação equivalente imposta pelo compilador porque NumberFormatException é não verificada.

Falhas verificadas frequentemente descrevem condições para as quais um chamador pode se preparar, como o desaparecimento de um arquivo. Falhas de execução frequentemente identificam defeitos ou argumentos inválidos. Essas são razões úteis de projeto, mas a cadeia de superclasses determina a categoria. Uma classe personalizada que estende RuntimeException permanece não verificada mesmo quando um chamador poderia se recuperar.

Identifique tratadores compatíveis por meio da herança

catch (IOException e) pode tratar uma FileNotFoundException ou NoSuchFileException. catch (Exception e) também captura exceções de execução; ele pode transformar um defeito de código em uma mensagem enganosa sobre a entrada. catch (Throwable e) também alcança o ramo Error e raramente é apropriado para uma recuperação comum.

Para classificar uma classe desconhecida, acompanhe sua herança para cima na documentação da API. InputMismatchException estende NoSuchElementException, que estende RuntimeException, portanto é não verificada. InterruptedException estende Exception fora do ramo de execução, portanto é verificada. Declarar um tipo não verificado em uma cláusula throws é permitido, mas não altera sua categoria.

Principais conclusões

  • RuntimeException, Error e todas as suas subclasses são não verificados.
  • Outras subclasses de Throwable são verificadas; o código que pode lançá-las deve capturá-las ou declará-las.
  • Exceções verificadas e não verificadas ocorrem em tempo de execução.
  • Uma captura para uma superclasse também corresponde às suas subclasses.
  • Um tratador abrangente de Exception pode ocultar defeitos de programação.
  • Classifique uma exceção desconhecida por sua cadeia de superclasses.
2

Trate exceções com try, catch e finally

Tratar uma falha altera quais instruções são executadas em seguida. Um tratador útil deve corresponder à exceção e deixar o programa pronto para continuar, enquanto a limpeza também deve ser executada nos caminhos que saem antecipadamente. Acompanhe conversões e laços passo a passo, escolha tratadores específicos antes dos gerais e coloque o bloco protegido em torno do trabalho que deve falhar em conjunto. Depois, acompanhe como finally se comporta quando uma exceção se propaga ou um método retorna.

2.1 Recupere a execução após uma conversão malsucedida

Um bloco try delimita um trabalho que pode falhar. Um bloco catch compatível dá ao programa uma próxima ação útil, como pedir outro valor. Tratar a exceção não repete a instrução que falhou automaticamente.

Acompanhe os ramos
System.out.println("A");
try {
    System.out.println("B");
    int value = Integer.parseInt("4x");
    System.out.println("C");
} catch (NumberFormatException e) {
    System.out.println("D: " + e.getMessage());
}
System.out.println("E");

A saída é A, B, D: For input string: "4x" e E, cada um em sua própria linha. A conversão falha, então Java ignora C e entra no tratador compatível. Quando esse tratador termina normalmente, a execução continua após toda a instrução. Se a conversão for bem-sucedida, o tratador é ignorado. Se o bloco lançar uma ArithmeticException, esse tratador não corresponderá a ela; a exceção se propagará.

Tente novamente com uma nova entrada

Leia uma linha inteira antes de convertê-la. O laço abaixo aceita um número inteiro e trata o fim da entrada do teclado informando que nenhum valor foi fornecido:

import java.util.Scanner;

class WholeNumbers {
    static int readWholeNumber(Scanner in) {
        while (in.hasNextLine()) {
            String line = in.nextLine();
            try {
                return Integer.parseInt(line.trim());
            } catch (NumberFormatException e) {
                System.out.println("Please enter a whole number.");
            }
        }
        throw new IllegalStateException("No number supplied");
    }
}

Para as entradas “vinte” e “20”, o tratador exibe a mensagem uma vez, o laço lê uma nova linha e o método retorna 20. trim() remove os caracteres de espaço em branco ao redor: sem isso, Integer.parseInt(" 20") falha. A conversão aceita um sinal opcional e algarismos que representam um inteiro dentro do intervalo permitido.

Um scanner baseado em unidades de entrada precisa de outra correção. Quando nextInt() encontra “dez”, sua InputMismatchException deixa essa unidade sem ser lida. Capturar a exceção e chamar nextInt() novamente repete a falha para sempre. Consuma a unidade inválida com next() ou descarte a linha com nextLine() antes de tentar novamente. hasNextInt() pode verificar uma unidade antes da conversão.

Mantenha o estado recuperado utilizável

Uma variável declarada dentro de try existe apenas nesse bloco. Se o código posterior precisar do resultado, declare-a fora e faça com que cada caminho que continua atribua um valor válido:

int quantity;
try {
    quantity = Integer.parseInt("bad");
} catch (NumberFormatException e) {
    quantity = 0;
}
System.out.println(quantity);

Zero só é adequado aqui se o programa o definir como uma alternativa válida. Deixar quantity sem atribuição no tratador causa um erro de atribuição definitiva em tempo de compilação.

Capture o tipo específico que você consegue tratar. Um tratador vazio perde o problema silenciosamente; um catch (Exception e) abrangente pode classificar um defeito de referência nula como um número inválido. A recuperação deve pedir outra entrada, ignorar um item, escolher um valor padrão válido, informar a falha ou repassar uma exceção significativa. Para limites simples e previsíveis, verifique primeiro: index >= 0 && index < list.size() impede índices de lista negativos e grandes demais.

Principais conclusões

  • Um tratador compatível é executado após o restante do bloco try que falhou ser ignorado.
  • Um laço deve ler uma nova entrada antes de tentar novamente.
  • Scanner.nextInt() deixa uma unidade de entrada incompatível sem ser lida.
  • Todo caminho que continua deve deixar as variáveis usadas depois inicializadas com valores adequados.

2.2 Escolha os tratadores e o trabalho que eles protegem

Um arquivo pode estar ausente, ilegível ou cheio de registros malformados. Essas falhas precisam de respostas diferentes. Vários tratadores permitem que um try as distinga, enquanto a posição do bloco determina quanto trabalho é interrompido quando algo falha.

Coloque os tratadores específicos primeiro

Java testa os tratadores de cima para baixo e executa o primeiro compatível. Ele não continua executando tratadores posteriores para a mesma exceção.

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;

class FirstCount {
    static void show(Path file) {
        try {
            int count = Integer.parseInt(Files.readString(file).trim());
            System.out.println(count);
        } catch (NoSuchFileException e) {
            System.out.println("File not found: " + file.toAbsolutePath());
        } catch (IOException e) {
            System.out.println("Could not read: " + file.toAbsolutePath());
        } catch (NumberFormatException e) {
            System.out.println("The file must contain one whole number.");
        }
    }
}

NoSuchFileException estende IOException, portanto deve vir primeiro. Inverter a ordem torna o tratador específico inalcançável e impede a compilação. A exceção de conversão não tem relação de herança com IOException, então esses dois tratadores podem aparecer em qualquer ordem.

Um tratador de exceção verificada também deve ser relevante para o trabalho protegido. Capturar IOException em torno apenas de int count = 5; é rejeitado porque esse bloco não pode lançá-la. Essa restrição não se aplica da mesma forma aos tipos não verificados ou aos tipos abrangentes Exception e Throwable.

Compartilhe um tratador quando a resposta for a mesma

Uma captura múltipla une tipos de exceção sem relação de herança com |:

try {
    String[] parts = "Ana".split(",");
    int age = Integer.parseInt(parts[1]);
    System.out.println(age);
} catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
    System.out.println("Invalid record: " + e.getMessage());
}

Aqui o segundo campo ausente provoca a exceção de índice. Um campo presente, mas não numérico, provocaria a exceção de conversão, e ambos recebem a mesma resposta. O parâmetro da captura múltipla é implicitamente final. As alternativas não podem ser uma subclasse e sua superclasse: FileNotFoundException | IOException é inválido porque IOException já abrange ambas.

Decida o que uma falha deve fazer o programa ignorar

Considere os textos “3”, “x” e “5”. Com um try em torno de todo o laço, o processamento para em “x” e a soma até então é 3. Coloque o try dentro do laço para recuperar a execução separadamente para cada item:

int sum = 0;
for (String text : new String[] {"3", "x", "5"}) {
    try {
        sum += Integer.parseInt(text);
    } catch (NumberFormatException e) {
        System.out.println("Skipped: " + text);
    }
}
System.out.println(sum);

Isso exibe Skipped: x e depois 8. O laço continua porque seu corpo tratou a falha daquele registro. Tratadores aninhados são procurados para fora a partir do bloco protegido mais interno; um tratador interno incompatível dá uma chance ao externo. Escolha a menor unidade de trabalho que deve falhar em conjunto: um registro para dados inválidos, a operação de arquivo para uma falha de leitura.

Principais conclusões

  • Java executa no máximo um tratador compatível para cada exceção.
  • Capture uma subclasse antes de sua superclasse.
  • A captura múltipla compartilha uma resposta entre tipos de exceção sem relação de herança.
  • A captura múltipla não pode combinar uma superclasse com sua subclasse.
  • Coloque a recuperação de falhas em registros dentro do laço para continuar com os registros posteriores.

2.3 Execute a limpeza antes da transferência de controle

Algum trabalho deve ocorrer independentemente de uma operação ter sucesso ou falhar. Um bloco finally é executado quando o controle sai de sua instrução try, inclusive quando uma exceção se propaga ou um método retorna.

Acompanhe uma exceção sem tratador compatível
try {
    System.out.println("1");
    int[] values = new int[2];
    values[2] = 7;
    System.out.println("2");
} catch (NumberFormatException e) {
    System.out.println("3");
} finally {
    System.out.println("4");
}
System.out.println("5");

Apenas 1 e 4 são exibidos antes de a ArrayIndexOutOfBoundsException se propagar. O índice 2 está fora do vetor de dois elementos. O tratador não é compatível, mas finally ainda é executado. A instrução que exibe 5 está fora do bloco de limpeza, portanto a exceção que se propaga faz com que ela seja ignorada.

Se o trabalho protegido lançar uma NumberFormatException compatível após exibir 1, o tratador exibirá 3, a limpeza exibirá 4 e a execução continuará até 5. Em um caminho bem-sucedido, nenhum tratador é executado, mas a limpeza ainda ocorre.

Valores de retorno são preparados antes da limpeza
class Cleanup {
    static int result() {
        try {
            return 1;
        } finally {
            System.out.println("cleanup");
        }
    }
}

A expressão de retorno é avaliada primeiro. Java então exibe cleanup, e o chamador recebe 1. Um break ou continue que sai de uma região protegida também executa sua limpeza antes que a transferência de controle ocorra.

Mantenha return fora de finally. Um return 2; ali substituiria o valor de retorno pendente e poderia até descartar uma exceção pendente. Uma exceção lançada pela limpeza também pode substituir a falha original. A limpeza não deve introduzir um segundo resultado concorrente. A opção -Xlint:finally do compilador emite um aviso quando um bloco finally não pode terminar normalmente.

Feche um objeto somente se ele tiver sido aberto

O padrão manual mais antigo precisa de uma variável visível ao bloco de limpeza:

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Scanner;

class ManualRead {
    static void firstLine(Path file) throws IOException {
        Scanner sc = null;
        try {
            sc = new Scanner(file, StandardCharsets.UTF_8);
            if (sc.hasNextLine()) System.out.println(sc.nextLine());
            if (sc.ioException() != null) throw sc.ioException();
        } finally {
            if (sc != null) sc.close();
        }
    }
}

Se a abertura falhar, sc ainda será null, portanto a verificação impede que a limpeza lance uma nova exceção de referência nula. Para objetos que podem ser fechados, try-with-resources elimina esse controle manual e lida com falhas concorrentes com mais segurança.

finally não é uma garantia contra a parada da máquina. System.exit encerra a JVM sem executar essa limpeza; uma falha ou perda de energia também a impede. Um laço infinito que nunca sai do bloco também nunca chega ao seu finally.

Principais conclusões

  • finally é executado na conclusão normal, em exceções capturadas e não capturadas e em transferências de controle como return.
  • Uma expressão de retorno é avaliada antes da execução da limpeza.
  • O código após uma instrução try é ignorado quando uma exceção se propaga; finally ainda é alcançado.
  • Um retorno ou uma exceção lançada em finally pode ocultar o resultado original.
  • Try-with-resources é a escolha usual para fechar recursos de arquivo.
  • O encerramento da JVM ou um bloco que nunca termina pode impedir a limpeza.
3

Lance exceções e projete suas próprias exceções

Uma solicitação inválida é mais fácil de diagnosticar antes que altere um objeto. Seus métodos podem rejeitar argumentos ou estados inválidos com exceções padrão e sinalizar problemas do domínio com classes personalizadas. A declaração do método informa aos chamadores sobre falhas verificadas; a herança limita o que uma sobrescrita pode acrescentar. Ao transformar uma falha de baixo nível em outra mais útil, preserve sua causa para que o chamador receba tanto o contexto quanto as evidências originais para o diagnóstico.

3.1 Sinalize argumentos e estados inválidos

Seus métodos podem rejeitar solicitações inválidas antes de alterar um objeto. Escolha uma exceção que identifique o problema e permita ao chamador responder.

Lance um objeto imediatamente
class Percentage {
    private int value;

    public void setPercentage(int value) {
        if (value < 0 || value > 100) {
            throw new IllegalArgumentException(
                "percentage must be 0 to 100, was " + value);
        }
        this.value = value;
    }
}

Chamar setPercentage(120) lança uma exceção com a mensagem percentage must be 0 to 100, was 120. A atribuição não foi executada, portanto o campo mantém seu valor anterior. Isso é falha imediata: informe a solicitação inválida no ponto em que você consegue explicá-la. A mesma verificação em um construtor impede que um objeto inválido seja retornado.

throw precisa de um objeto de exceção, como em throw new IllegalArgumentException("bad quantity");. Um nome de classe sozinho não é um objeto. Uma instrução comum diretamente após um throw incondicional no mesmo bloco é inalcançável.

ProblemaExceção padrão
O argumento tem um valor inválidoIllegalArgumentException
O objeto está no estado inadequado para a chamadaIllegalStateException
Uma referência a objeto obrigatória é nullNullPointerException
A operação não é oferecida pela classeUnsupportedOperationException
A posição está fora de uma coleçãoIndexOutOfBoundsException

Objects.requireNonNull(name, "name must not be null"), de java.util.Objects, é uma forma prática de verificar se uma referência é nula. Um pedido já enviado que rejeita outro item representa um problema de estado; uma quantidade negativa de itens é um problema de argumento.

Declare o que pode sair do método

Um método auxiliar de leitura de arquivos pode declarar sua falha verificada:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

class NameLoader {
    static List<String> loadNames(Path file) throws IOException {
        return Files.readAllLines(file);
    }
}

throw é uma instrução executável. throws pertence à declaração do método e informa aos chamadores quais falhas verificadas eles devem tratar. Ela não captura uma falha nem faz o método continuar depois dela. Cada chamador deve capturar IOException ou declará-la por sua vez. Uma captura também pode relançar o mesmo objeto com throw e;.

Capture a exceção onde uma resposta útil for possível. Um método auxiliar geralmente não pode pedir ao usuário que selecione outro arquivo, mas main pode. Exibir “erro” e retornar uma lista vazia confundiria um arquivo ausente com um arquivo realmente vazio. Em um pequeno experimento, main pode declarar throws IOException; um programa finalizado trata falhas esperadas com mensagens úteis. Tipos não verificados podem ser declarados para documentação, embora o compilador não exija isso.

Respeite o contrato herdado

Se uma interface declarar read() throws IOException, um método que o sobrescreve pode declarar IOException, uma subclasse verificada mais específica ou nenhuma exceção verificada. Ele não pode ampliar a declaração para Exception. Pode declarar tipos não verificados. Uma sobrescrita de Object.toString() não pode adicionar IOException, pois o método herdado não declara exceções verificadas. Chamadas por meio do tipo da interface ainda devem tratar a IOException declarada, mesmo quando uma implementação não declara nenhuma.

Principais conclusões

  • Use throw com um objeto de exceção para interromper uma operação inválida.
  • Valide antes de alterar campos ou coleções.
  • throws declara uma possível falha; não a trata.
  • Capture a exceção onde uma recuperação útil for possível; caso contrário, passe a falha ao chamador.
  • Métodos que sobrescrevem outros não podem adicionar exceções verificadas novas ou mais abrangentes.

3.2 Descreva falhas do domínio e preserve suas causas

Uma exceção padrão muitas vezes é suficiente. Crie uma classe personalizada quando os chamadores precisarem reconhecer um problema específico do programa, como estoque insuficiente ou um registro de dados malformado, e responder a ele de forma diferente.

Escolha a superclasse de forma intencional

Estender Exception cria uma exceção verificada. Estender RuntimeException cria uma exceção não verificada. Use a opção verificada quando os chamadores devem se preparar para uma falha recuperável do domínio; use a opção não verificada para uso incorreto ou um defeito de programação.

class OutOfStockException extends Exception {
    public OutOfStockException(String message) {
        super(message);
    }
}

super(message) armazena a mensagem no mecanismo de exceção herdado, então getMessage() a retorna. Por convenção, o nome da classe termina em Exception. Campos adicionais e métodos de acesso podem apresentar detalhes estruturados, como as quantidades solicitada e disponível.

Mantenha o estoque inalterado após uma falha
import java.util.HashMap;

class Inventory {
    private final HashMap<String, Integer> stock = new HashMap<>();

    Inventory() {
        stock.put("pens", 12);
    }

    void remove(String item, int quantity) throws OutOfStockException {
        if (quantity <= 0) {
            throw new IllegalArgumentException("quantity must be positive");
        }
        int available = stock.getOrDefault(item, 0);
        if (quantity > available) {
            throw new OutOfStockException("Requested " + quantity
                + " of " + item + ", only " + available + " in stock");
        }
        stock.put(item, available - quantity);
    }
}

Começando com 12 canetas, remover 5 deixa 7. Uma solicitação posterior de 10 lança uma exceção, e 7 permanecem porque a atualização vem depois de todas as verificações. O chamador deve tratar ou declarar a falha verificada de estoque; a falha de quantidade inválida é não verificada. Um programa que precise de uma resposta distinta para um item desconhecido poderia usar uma UnknownItemException relacionada, com ambos os tipos do domínio sob uma classe base InventoryException.

Encapsule sem perder o problema original

Um analisador pode transformar uma falha de conversão de baixo nível em uma falha em um registro:

class InvalidRecordException extends Exception {
    public InvalidRecordException(String message) {
        super(message);
    }
    public InvalidRecordException(String message, Throwable cause) {
        super(message, cause);
    }
}

Dentro do método de análise e conversão, um tratador pode fazer isto:

catch (NumberFormatException e) {
    throw new InvalidRecordException(
        "Line 3: quantity is not a number: x", e);
}

O encapsulador fornece ao chamador uma categoria significativa e o número da linha. Seu getCause() retorna a NumberFormatException original, e um rastreamento exibido preserva uma seção Caused by:. Construir uma nova exceção apenas com a mensagem antiga perde o objeto original e seu rastreamento.

java.io.UncheckedIOException é um encapsulador não verificado pronto, específico para IOException. Seus construtores aceitam a causa, com uma mensagem opcional. Ele pode transportar uma falha de arquivo por uma sobrescrita que não pode adicionar uma declaração de exceção verificada. O encapsulamento altera o tipo que o chamador vê; não corrige o problema do arquivo. Mantenha decisões comuns de laço como condições e break, sem criar exceções para o fluxo rotineiro.

Principais conclusões

  • Classes personalizadas permitem que chamadores reconheçam falhas significativas do domínio.
  • Estenda Exception para uma classe verificada ou RuntimeException para uma classe não verificada.
  • Chame super(message) para preservar uma mensagem útil para o diagnóstico.
  • Valide toda a solicitação antes de atualizar o estado.
  • Passe a exceção original como causa ao encapsulá-la.
  • UncheckedIOException transporta uma IOException como uma falha não verificada.
4

Localize arquivos e feche recursos com segurança

Um arquivo de texto deve ser encontrado, decodificado e fechado corretamente. Um caminho relativo depende do diretório de trabalho, enquanto bytes só se tornam caracteres legíveis por meio da codificação correta. Texto numérico e terminadores de linha trazem suas próprias escolhas de portabilidade. Depois que um arquivo é aberto, try-with-resources o libera em toda saída e mantém a falha principal visível caso o fechamento também falhe. Essas escolhas tornam o código posterior de leitura e gravação mais confiável.

4.1 Faça arquivos de texto funcionarem em diferentes computadores

Um arquivo armazena bytes, enquanto seu programa trabalha com caracteres e números. Uma leitura bem-sucedida precisa da localização correta, da codificação de caracteres correta e de uma convenção clara para linhas e texto numérico.

Encontre a localização real

Um caminho relativo parte do diretório de trabalho do programa. Ele não parte da pasta que contém o código-fonte. Um caminho absoluto parte da raiz do sistema de arquivos, como /home/ana/data/scores.txt, ou da raiz de uma unidade no Windows.

Path file = Path.of("data", "scores.txt");
System.out.println(System.getProperty("user.dir"));
System.out.println(file.toAbsolutePath());
System.out.println(file.getFileName());

Importe java.nio.file.Path. Criar esse Path não abre nada nem verifica se algo existe. toAbsolutePath() revela onde Java procurará, e getFileName() fornece scores.txt. Uma IDE frequentemente usa a pasta do projeto como diretório de trabalho. Barras normais em "data/scores.txt" funcionam no Windows, Linux e macOS. Um literal de caminho do Windows que usa barras invertidas precisa de escape, como em "C:\\data\\scores.txt". A classe mais antiga java.io.File também representa uma localização; converta com toPath() ou toFile().

Associe bytes a caracteres

UTF-8 codifica todos os caracteres Unicode. Caracteres latinos básicos ocupam um byte; os demais ocupam de dois a quatro. O texto “café” contém quatro caracteres, mas cinco bytes em UTF-8 porque “é” ocupa dois. Ler esses bytes como ISO-8859-1 pode produzir “café”. Use a codificação que foi usada na gravação.

Os métodos de texto de Files usam UTF-8 por padrão. Classes como FileWriter e um scanner aberto sem uma codificação usam a codificação de caracteres padrão, que passou a ser UTF-8 no Java 18; instalações mais antigas podem ser diferentes. StandardCharsets.UTF_8, de java.nio.charset, torna a escolha explícita. Bytes inválidos lidos por Files.readAllLines produzem MalformedInputException, uma subclasse de IOException.

Leia linhas sem deixar terminadores
ConvençãoEscape em cadeia de caracteres Java
Terminador de linha do Linux e macOS\n
Terminador de linha típico do Windows\r\n

Com um terminador após cada linha, “a” e “b” precisam de quatro bytes com terminadores LF e seis com terminadores CRLF. BufferedReader.readLine(), Files.readAllLines e Scanner.nextLine() removem terminadores de linha reconhecidos. Dividir uma cadeia completa com split("\n") deixa o \r do Windows, então converter "12\r" com parseInt falha. Prefira métodos de leitura de linhas ou remova os espaços do texto. System.lineSeparator() e o formato %n produzem o terminador do sistema atual.

Mantenha a consistência em arquivos numéricos

Integer.parseInt aceita texto inteiro, sem separador decimal. Double.parseDouble("3.5") aceita um ponto; Double.parseDouble("3,5") falha. Esses métodos de análise e conversão ignoram a configuração regional. Os métodos numéricos de Scanner e a formatação decimal comum seguem a configuração regional, então configurações alemãs ou holandesas podem esperar “3,5” e produzir “3,50”. Use scanner.useLocale(Locale.ROOT) e String.format(Locale.ROOT, "%.2f", value) para dados com ponto decimal; importe java.util.Locale.

Localizações inexistentes normalmente produzem NoSuchFileException com Files ou Scanner(Path), enquanto construtores mais antigos que recebem nomes de arquivo podem produzir FileNotFoundException. Falhas de permissão podem produzir AccessDeniedException. Essas são falhas verificadas de entrada e saída: uma expressão de caminho correta, por si só, não pode impedi-las.

Principais conclusões

  • Caminhos relativos são resolvidos a partir do diretório de trabalho.
  • Criar um Path não abre nem verifica o arquivo.
  • Use a mesma codificação na leitura e na gravação; escolha UTF-8 explicitamente onde os padrões podem variar.
  • Métodos de leitura de linhas removem terminadores LF, CRLF e CR.
  • Double.parseDouble usa ponto; métodos numéricos sensíveis à configuração regional precisam de uma configuração escolhida.
  • Abrir e ler arquivos ainda exige tratamento de exceções verificadas.

4.2 Deixe Java fechar cada recurso aberto

Um arquivo aberto usa um recurso do sistema operacional. Fechá-lo libera o recurso e descarrega a saída pendente de um gravador. Esquecer o fechamento pode esgotar os limites de arquivos abertos, perder texto armazenado em buffer ou impedir que outro programa altere o arquivo.

Declare recursos no cabeçalho do try
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

class Lines {
    static void show(Path file) throws IOException {
        try (BufferedReader in =
                Files.newBufferedReader(file, StandardCharsets.UTF_8)) {
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
        }
    }
}

O cabeçalho abre o leitor. O corpo o usa, e Java o fecha quando o corpo termina normalmente, retorna ou lança uma exceção. Não é necessário um finally separado. Não há tratador aqui, portanto qualquer falha verificada ainda passa ao chamador por meio de throws IOException.

Um recurso deve implementar AutoCloseable. Essa interface declara close() e permite Exception; sua subinterface Closeable restringe a falha verificada declarada a IOException. Leitores, gravadores e Scanner atendem a esse requisito. Uma String não. Variáveis do cabeçalho são implicitamente final e estão disponíveis no corpo, não nos blocos catch ou finally dessa instrução. Java 9 e versões posteriores também permitem uma variável existente final ou efetivamente final: try (in) { ... }.

Feche na ordem inversa

Separe os recursos com pontos e vírgulas:

try (BufferedReader in = Files.newBufferedReader(source);
     java.io.BufferedWriter out = Files.newBufferedWriter(target)) {
    String line;
    while ((line = in.readLine()) != null) {
        out.write(line);
        out.newLine();
    }
}

Este é um bloco dentro de um método que declara IOException, com caminhos distintos source e target. Java abre in primeiro, depois out, e fecha out antes de in. Se a abertura de out falhar, o leitor já aberto ainda será fechado. Abrir um gravador no caminho de entrada truncaria essa entrada, portanto os caminhos devem ser diferentes para essa cópia direta.

O fechamento dos recursos ocorre antes das cláusulas catch e finally pertencentes à mesma instrução. Esses tratadores podem receber falhas da abertura, do uso ou do fechamento dos recursos.

Mantenha a falha principal visível

Suponha que o corpo lance uma exceção de registro e, em seguida, o fechamento do leitor lance uma IOException. Try-with-resources propaga a exceção do corpo e associa a falha de fechamento como suprimida. getSuppressed() a recupera, e o rastreamento exibe uma seção Suppressed:. A falha original do corpo permanece visível. Se o corpo tiver sucesso e apenas o fechamento falhar, a exceção de fechamento se propagará normalmente.

Com várias falhas durante o fechamento, Java ainda tenta os fechamentos restantes. Um simples finally { resource.close(); } pode, em vez disso, substituir uma falha pendente do corpo por uma falha de limpeza.

Use esse padrão para recursos de arquivo que pertencem ao seu código. Fechar um scanner sobre System.in também fecha a entrada de teclado do programa, impedindo leituras posteriores. Mantenha a responsabilidade pela entrada padrão compartilhada no nível do programa em vez de fechá-la em um método auxiliar.

Principais conclusões

  • Try-with-resources fecha recursos abertos com sucesso em saídas normais e excepcionais.
  • Somente objetos AutoCloseable podem ser recursos.
  • Os recursos são abertos da esquerda para a direita e fechados da direita para a esquerda.
  • O fechamento precede os blocos catch e finally da mesma instrução.
  • Uma falha do corpo permanece como principal; falhas posteriores de fechamento são suprimidas.
  • O fechamento automático não substitui o tratamento pela regra de capturar ou declarar.
  • Fechar um scanner também fecha sua fonte de entrada, se ela puder ser fechada.
5

Leia e grave arquivos de texto

O processamento de arquivos conecta bytes externos aos objetos e resultados que seu programa usa. Leia linhas com um método adequado ao tamanho da entrada, valide os campos antes da conversão e grave com uma escolha consciente entre substituição e acréscimo ao final. Um relatório completo precisa de respostas distintas para um registro inválido e um arquivo inutilizável. Construa o resultado antes de salvá-lo e use uma saída temporária e uma movimentação atômica suportada quando um destino existente precisar ser protegido.

5.1 Leia linhas e transforme-as em objetos

A leitura fornece texto. A análise e conversão dão significado a esse texto: uma contagem, uma idade ou um objeto. Mantenha essas duas operações separadas para que um registro inválido não pareça uma falha de leitura do arquivo.

Escolha quanto manter na memória
MétodoResultado e uso
Files.readAllLines(path)Uma lista com todas as linhas; conveniente para arquivos pequenos
Files.readString(path)Uma cadeia de caracteres que preserva os terminadores de linha
BufferedReader.readLine()Uma linha por vez; null sinaliza o fim
Scanner.hasNextLine() / nextLine()Leitura conveniente linha por linha

Importe java.nio.file.Files e Path, além dos tipos de leitor ou coleção que você usar. Os métodos de texto de Files usam UTF-8 por padrão. Um BufferedReader deve ficar em try-with-resources e informa falhas de leitura com IOException. Ler uma linha por vez evita manter toda a entrada na memória, a menos que seu processamento armazene todos os registros depois.

Um scanner também precisa ser fechado e requer uma verificação adicional de falha:

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Scanner;

class ScanFile {
    static void show(Path file) throws IOException {
        try (Scanner sc = new Scanner(file, StandardCharsets.UTF_8)) {
            while (sc.hasNextLine()) {
                System.out.println(sc.nextLine());
            }
            if (sc.ioException() != null) throw sc.ioException();
        }
    }
}

A abertura pode lançar uma exceção diretamente. Durante a leitura, Scanner trata uma falha subjacente de entrada e saída como fim da entrada e a armazena; ioException() a disponibiliza. Sem essa verificação final, uma leitura parcial pode parecer bem-sucedida.

Conte as linhas físicas e depois analise e converta

Para as linhas de entrada “12”, “15”, “abc”, uma linha vazia e “9”, incremente o número da linha antes de decidir se uma linha em branco será ignorada. Converta cada linha não vazia com Integer.parseInt(line.trim()) dentro de seu próprio try. Informe “Line 3: not a number: abc” e continue. A soma válida é 36 e a contagem é 3, resultando em média 12,0. Calcule (double) sum / count para preservar um resultado fracionário e verifique primeiro se a contagem não é zero.

Verifique os campos antes de acessar por índice

Dados simples separados por vírgulas podem se tornar objetos. Aqui a primeira linha é um cabeçalho obrigatório; cada registro restante tem um nome não vazio e uma idade inteira:

String[] parts = line.split(",", -1);
if (parts.length != 2 || parts[0].isBlank() || parts[1].isBlank()) {
    System.out.println("Line " + lineNumber + ": expected name and age");
    continue;
}
try {
    int age = Integer.parseInt(parts[1].trim());
    people.add(new Person(parts[0].trim(), age));
} catch (NumberFormatException e) {
    System.out.println("Line " + lineNumber + ": invalid age");
}

Este trecho do corpo de um laço pressupõe line, lineNumber, uma List<Person> chamada people e um construtor Person(String, int). Ignore o cabeçalho “name,age” antes dessa etapa de análise e conversão; caso contrário, “age” falhará na conversão numérica. Os registros “Ana,34”, “Ben,29” e “Chen,41” totalizam 104 anos e têm média de aproximadamente 34,67.

Um simples split(",") descarta campos vazios no final: “Eve,” produz apenas uma parte. O limite -1 mantém o segundo campo vazio para que a validação possa informá-lo. Sempre verifique o comprimento antes de parts[1]. A divisão por si só não trata vírgulas entre aspas, como no nome em “"Smith, Ana",34”; o formato CSV completo precisa de um analisador de CSV.

Principais conclusões

  • Escolha métodos que leem o arquivo inteiro para entradas de tamanho gerenciável ou um laço de leitura para entradas grandes.
  • Verifique Scanner.ioException() após a leitura para detectar uma falha de leitura oculta.
  • Conte as linhas originais do arquivo mesmo quando linhas em branco ou registros forem ignorados.
  • Verifique o número de campos e os valores obrigatórios antes de acessar por índice e converter.
  • Ignore um cabeçalho antes de analisar e converter os registros.
  • Uma divisão simples não consegue analisar campos CSV entre aspas.

5.2 Grave o texto completo e acrescente conteúdo de forma intencional

Abrir um arquivo de saída pode alterá-lo imediatamente. Escolha entre substituição e acréscimo ao final antes de abrir o gravador e termine fechando-o para que a saída armazenada em buffer não fique na memória.

Substitua ou acrescente ao final

Files.writeString(path, text) grava uma cadeia de caracteres. Files.write(path, lines) grava uma sequência iterável de linhas, adicionando o separador de linha do sistema após cada uma, incluindo a última. Com as opções padrão, ambos criam um arquivo ausente e truncam um existente.

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

class RunLog {
    static void recordStart(Path log) throws IOException {
        Files.writeString(log, "started" + System.lineSeparator(),
            StandardCharsets.UTF_8,
            StandardOpenOption.CREATE, StandardOpenOption.APPEND);
    }
}

CREATE permite criar um novo arquivo; APPEND preserva o conteúdo antigo e adiciona ao final. APPEND sozinho falha se o arquivo estiver ausente. O acréscimo não insere um separador ausente antes do seu texto: se um arquivo existente terminar no meio de uma linha, os próximos caracteres continuarão essa linha.

O FileWriter mais antigo tem um indicador de acréscimo: new FileWriter("log.txt", StandardCharsets.UTF_8, true). Sem acréscimo, um novo FileWriter ou um PrintWriter criado com nome de arquivo também trunca um arquivo existente. Nunca abra um gravador que substitui o conteúdo em uma entrada que você ainda precisa ler.

Escolha um gravador e perceba as falhas

BufferedWriter oferece write e newLine() e informa falhas de gravação como exceções verificadas:

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Locale;

class ReportWriter {
    static void write(Path file) throws IOException {
        try (BufferedWriter out =
                Files.newBufferedWriter(file, StandardCharsets.UTF_8)) {
            out.write("Readings: 3");
            out.newLine();
            out.write(String.format(Locale.ROOT, "Average: %.2f", 3.0));
            out.newLine();
        }
    }
}

O arquivo tem duas linhas: “Readings: 3” e “Average: 3.00”. Locale.ROOT fixa o ponto decimal. newLine(), println e %n usam o terminador de linha da plataforma; um \n literal grava LF em todos os sistemas.

Um PrintWriter oferece os convenientes print, println e printf, mas esses métodos registram falhas de entrada e saída em vez de lançá-las. checkError() descarrega o buffer e informa seu indicador de erro. Para verificar também falhas no fechamento final, mantenha acesso ao gravador e verifique após fechá-lo. Para código que precisa propagar falhas de gravação de forma confiável, use BufferedWriter ou os métodos de Files.

Complete o ciclo de gravação e leitura

Gravadores armazenam a saída em buffer. flush() envia o texto pendente adiante; close() descarrega o buffer e libera o arquivo. Try-with-resources garante que o fechamento seja tentado em toda saída, mas não pode fazer uma gravação em disco ter sucesso.

Para salvar uma pessoa, grave o nome, uma vírgula e a idade inteira, seguidos de um terminador de linha. Formate decimais com Locale.ROOT para que um Double.parseDouble posterior possa lê-los. Um diretório ancestral ausente não é criado pela abertura de um arquivo: use Files.createDirectories(folder) quando a intenção for criá-lo ou informe a falha. Uma gravação pode falhar após truncar o arquivo ou produzir uma saída parcial; use uma saída temporária e uma movimentação atômica quando o destino precisar ser protegido.

Principais conclusões

  • A gravação padrão cria um arquivo ausente e trunca um existente.
  • Use CREATE com APPEND para preservar o conteúdo antigo e permitir um novo arquivo de registro.
  • O fechamento descarrega a saída armazenada em buffer e libera o recurso.
  • PrintWriter registra erros de gravação; checkError() os disponibiliza.
  • BufferedWriter e os métodos de Files propagam falhas de entrada e saída.
  • Use UTF-8 e Locale.ROOT para um ciclo portátil de gravação e leitura de texto.
  • Gravar um arquivo não cria pastas ancestrais ausentes.

5.3 Construa um relatório sem ocultar falhas

Um processador robusto de arquivos precisa de dois níveis de recuperação. Um registro inválido pode ser ignorado e informado; uma falha ao ler ou salvar o arquivo interrompe a tarefa. Calcule um resultado completo antes de alterar seu destino.

Leia, valide, calcule e salve

O programa completo abaixo lê o cabeçalho opcional “date,temperature” seguido de registros simples com dois campos. As datas são identificadores não vazios; as temperaturas são números finitos em graus Celsius. Ele ignora e informa registros malformados, incluindo linhas em branco. A exceção verificada aninhada mantém problemas de registro separados de problemas de arquivo.

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.AtomicMoveNotSupportedException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.List;
import java.util.Locale;

public class TemperatureReport {
    static class InvalidRecordException extends Exception {
        InvalidRecordException(String message) { super(message); }
        InvalidRecordException(String message, Throwable cause) {
            super(message, cause);
        }
    }

    static List<String> readLines(Path file) throws IOException {
        return Files.readAllLines(file, StandardCharsets.UTF_8);
    }

    static double parseTemperature(String line, int lineNumber)
            throws InvalidRecordException {
        String[] parts = line.split(",", -1);
        if (parts.length != 2 || parts[0].isBlank()
                || parts[1].isBlank()) {
            throw new InvalidRecordException("Line " + lineNumber
                + ": expected a date label and a temperature");
        }
        try {
            double value = Double.parseDouble(parts[1].trim());
            if (!Double.isFinite(value)) {
                throw new InvalidRecordException("Line " + lineNumber
                    + ": temperature must be finite");
            }
            return value;
        } catch (NumberFormatException e) {
            throw new InvalidRecordException("Line " + lineNumber
                + ": not a number: " + parts[1], e);
        }
    }

    static String summarize(List<String> lines) {
        int count = 0;
        int skipped = 0;
        double sum = 0;
        double min = Double.POSITIVE_INFINITY;
        double max = Double.NEGATIVE_INFINITY;
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            if (i == 0 && line.equals("date,temperature")) continue;
            try {
                double value = parseTemperature(line, i + 1);
                sum += value;
                count++;
                min = Math.min(min, value);
                max = Math.max(max, value);
            } catch (InvalidRecordException e) {
                skipped++;
                System.err.println(e.getMessage());
            }
        }
        if (count == 0) {
            return String.format(Locale.ROOT,
                "No valid readings%nSkipped lines: %d%n", skipped);
        }
        return String.format(Locale.ROOT,
            "Valid readings: %d%nAverage (°C): %.2f%n"
                + "Minimum (°C): %.2f%nMaximum (°C): %.2f%n"
                + "Skipped lines: %d%n",
            count, sum / count, min, max, skipped);
    }

    static void writeSummary(Path file, String text) throws IOException {
        Path target = file.toAbsolutePath();
        Path temp = Files.createTempFile(target.getParent(), "report-", ".tmp");
        try {
            Files.writeString(temp, text, StandardCharsets.UTF_8);
            Files.move(temp, target, StandardCopyOption.ATOMIC_MOVE);
        } catch (IOException e) {
            try {
                Files.deleteIfExists(temp);
            } catch (IOException cleanup) {
                e.addSuppressed(cleanup);
            }
            throw e;
        }
    }

    public static void main(String[] args) {
        Path input = Path.of("readings.csv");
        Path output = Path.of("summary.txt");
        try {
            List<String> lines = readLines(input);
            String report = summarize(lines);
            writeSummary(output, report);
            System.out.println("Saved: " + output.toAbsolutePath());
        } catch (NoSuchFileException e) {
            System.err.println("File or folder not found: " + e.getFile());
        } catch (AtomicMoveNotSupportedException e) {
            System.err.println("Could not save atomically: "
                + output.toAbsolutePath());
        } catch (IOException e) {
            System.err.println("Could not process " + input.toAbsolutePath()
                + " or save " + output.toAbsolutePath() + ": " + e.getMessage());
        }
    }
}
Acompanhe uma execução

Use estas cinco linhas de entrada sem cabeçalho:

2026-03-01,4.5
2026-03-02,6.0
2026-03-03,abc
2026-03-04,-1.5
missing comma

As linhas 1, 2 e 4 produzem três leituras válidas. A soma é 9,0; a média é 3,00 °C, o mínimo é -1,50 °C e o máximo é 6,00 °C. As linhas 3 e 5 produzem mensagens de diagnóstico, e o relatório registra duas linhas ignoradas. O tratador de análise e conversão fica dentro do laço, portanto cada registro inválido permite que os registros posteriores sejam alcançados. Atualizar os totais somente após uma análise e conversão bem-sucedida mantém os valores rejeitados fora deles.

Double.parseDouble aceita cadeias especiais como “NaN” e “Infinity”. Double.isFinite as rejeita aqui porque elas não podem servir como temperaturas medidas comuns. Um arquivo vazio, um arquivo com apenas o cabeçalho ou registros todos inválidos chegam ao ramo de contagem zero antes da divisão ou do uso do mínimo e máximo iniciais.

Proteja o destino

A leitura e o cálculo terminam antes do início da gravação. Files.writeString abre e fecha seu próprio arquivo, mas pode falhar depois de gravar parte dele. O programa, portanto, grava em um arquivo temporário na pasta de destino, fecha-o e solicita ATOMIC_MOVE. A movimentação torna o resultado concluído visível em uma única operação do sistema de arquivos, quando suportada.

A substituição atômica de um destino existente depende da implementação. O programa informa uma movimentação ou substituição não suportada e nunca tenta novamente com uma movimentação não atômica. Uma falha de limpeza é associada à exceção original em vez de substituí-la. A visibilidade atômica não garante a preservação dos dados após uma perda de energia.

Verificar Files.exists(input) antecipadamente não pode garantir a leitura posterior: um arquivo pode desaparecer ou se tornar inacessível após a verificação. Trate a operação efetiva. Antes de confiar em um processador, teste uma entrada ausente, pastas de saída ausentes, arquivos vazios e com apenas cabeçalho, terminadores CRLF, texto acentuado e registros malformados. Mensagens ao usuário devem indicar o caminho que falhou; a depuração de um encapsulador também precisa de sua causa original e de seu rastreamento da pilha.

Principais conclusões

  • Trate falhas em registros dentro do laço e falhas no processamento do arquivo inteiro fora dele.
  • Valide um registro completo antes de atualizar contagens ou totais.
  • Verifique se há zero registros válidos antes de calcular uma média.
  • Conclua a leitura e o cálculo antes de abrir a saída.
  • Grave e feche um arquivo temporário e solicite uma movimentação atômica para proteger o destino.
  • Informe a substituição atômica não suportada em vez de recorrer silenciosamente a outra opção.
  • Mantenha as causas originais e as falhas de limpeza disponíveis para diagnóstico.

Exercícios resolvidos de Exceções em Java

5 Lições Interativas

1

Acompanhe uma falha até sua causa

11 passos
Interprete um rastreamento de exceção, relacione-o às chamadas ativas e use a herança para classificar a falha.
  1. 1
    IntroduçãoUm programa pode compilar e ainda falhar

    Um valor de entrada pode fazer código Java válido falhar durante a execução. O objeto de exceção informa que tipo de problema ocorreu, e o rastreamento da pilha mostra quais chamadas de método estavam ativas.

    Acompanhe primeiro uma conversão inteira malsucedida. Depois, use as mesmas regras de herança que permitem usar objetos de subclasse como objetos de superclasse para decidir o que o compilador exige que você trate.

  2. 2
    ExemploObserve a conversão ser interrompida

    Um método loadCount executa estas instruções:

    System.out.print("start ");
    int count = Integer.parseInt("eight");
    System.out.print("finish");
    

    Ele exibe start e depois lança NumberFormatException. A atribuição não é concluída, e finish é ignorado. Um tratador compatível pode assumir o controle, mas a instrução que falhou não é retomada após a recuperação.

  3. 3
    ExplicaçãoAcompanhe as chamadas ativas

    Suponha que main tenha chamado loadCount, que chamou Integer.parseInt. Essas chamadas fazem parte da pilha de chamadas. A exceção se propaga para fora quando um método não tem um tratador compatível.

    parseInt falha primeiro, loadCount não consegue concluir seu trabalho normal e o chamador tem a chance de tratar a falha. Se ela sair de main sem tratamento, Java informa a exceção e a thread principal termina.

  4. 4
    ExemploEncontre seu primeiro registro de ativação

    Um rastreamento pode incluir estes registros da aplicação após os registros da biblioteca de Java:

    at Counts.loadCount(Counts.java:14)
    at Counts.main(Counts.java:5)
    

    Examine primeiro a linha 14: essa é a chamada em seu código mais próxima do ponto de detecção. A linha 5 informa onde loadCount foi chamado. A primeira linha da exceção fornece sua classe e mensagem; não confunda o registro do chamador abaixo com a instrução que primeiro usou o texto inválido.

  5. 5
    DesafioIdentifique a saída ignorada

    Um método auxiliar exibe A, chama Integer.parseInt("q2") e depois exibiria B. Seu chamador captura NumberFormatException e exibe C. Quais letras são exibidas e por quê?

    ---reveal---

    A e depois C. A conversão lança uma exceção antes de B; a propagação leva a falha ao tratador compatível do chamador. As instruções restantes do método auxiliar são abandonadas, portanto a recuperação não retorna para exibir B.

  6. 6
    DicaOlhe além da instrução detectada

    A instrução em que uma falha é detectada pode estar usando um valor inválido criado anteriormente. Uma falha de referência nula indica que você deve investigar onde essa referência deveria ter recebido um objeto.

    Use getMessage() para obter o texto de diagnóstico e printStackTrace() para a cadeia de chamadas. Uma mensagem pode ser null; uma seção Caused by: fornece outra exceção preservada dentro de um encapsulador.

  7. 7
    ExplicaçãoUse a cadeia de superclasses

    Throwable é a classe base dos objetos que podem ser lançados. Seus ramos principais são Error e Exception; RuntimeException está abaixo de Exception.

    RuntimeException, Error e todas as subclasses de ambos são não verificados. Outras subclasses de Throwable são verificadas. Ambas as categorias falham durante a execução; “verificada” descreve a verificação do tratamento pelo compilador, não um momento diferente em que a exceção é lançada.

  8. 8
    ExemploCompare um analisador e um leitor de arquivos

    NumberFormatException estende IllegalArgumentException, que estende RuntimeException, portanto uma chamada de Integer.parseInt não exige um tratador obrigatório.

    IOException estende Exception fora desse ramo. Uma chamada de Files.readString deve capturar sua possível IOException ou declará-la com throws. Um arquivo pode falhar por razões externas mesmo quando o código que o chama está correto.

  9. 9
    DesafioClassifique uma falha desconhecida

    BadRecordException estende Exception diretamente. Um método auxiliar declara que pode lançar esse tipo. O que seu chamador deve fazer e quando essa obrigação é verificada?

    ---reveal---

    Capturá-la ou declarar um tipo verificado aplicável na declaração do método chamador. O compilador impõe essa obrigação porque a classe está fora dos ramos não verificados. O sucesso de uma execução específica não elimina a exigência na declaração.

  10. 10
    DesafioExplique um tratador surpreendentemente abrangente

    Um bloco de leitura de arquivo captura Exception e exibe “Problema no arquivo”. Em vez disso, ele falha com uma NullPointerException causada por um defeito. O tratador receberá a exceção, e essa mensagem é confiável?

    ---reveal---

    Sim: NullPointerException estende RuntimeException, que estende Exception. A mensagem é enganosa porque essa falha é um defeito no código, não uma evidência de problema no arquivo. Leia o rastreamento e restrinja o tratador esperado às falhas que ele pode explicar.

  11. 11
    RecapitulaçãoEscolha a próxima ação de depuração

    Comece a investigação de uma falha por sua classe, mensagem e primeiro registro de ativação da aplicação. Acompanhe os chamadores e a origem dos valores inválidos quando a instrução detectada, sozinha, não explicar a causa.

    Depois, verifique a herança antes de escolher o tratamento: falhas verificadas exigem uma decisão visível ao compilador; defeitos não verificados ainda precisam de correção. Evite que tratadores abrangentes disfarcem um tipo de problema como outro.

2

Acompanhe caminhos de recuperação e limpeza

12 passos
Acompanhe uma conversão de entrada malsucedida, escolha o escopo e a ordem dos tratadores e acompanhe finally em saídas antecipadas.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoDecida o que deve acontecer em seguida
  2. 2
    ExemploRecupere a execução após toda a instrução
  3. 3
    DicaFaça a nova tentativa ler um novo texto
  4. 4
    DesafioCorrija o scanner preso
  5. 5
    ExplicaçãoDê uma resposta própria a uma falha específica
  6. 6
    ExemploDeixe o laço continuar
  7. 7
    DesafioMova o limite da região protegida
  8. 8
    Ideia-chaveCompartilhe respostas sem sobrepor tipos
  9. 9
    ExplicaçãoA limpeza é executada antes da saída
  10. 10
    DesafioAcompanhe uma falha sem tratador compatível
  11. 11
    DesafioImpeça que a limpeza oculte uma falha que exige nova tentativa
  12. 12
    RecapitulaçãoAcompanhe a próxima instrução alcançável
3

Rejeite uma solicitação sem danificar o estado

11 passos
Valide uma operação de estoque, sinalize uma falha do domínio e encapsule uma falha de análise e conversão preservando sua causa.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoPreserve um objeto utilizável
  2. 2
    ExemploValide antes da subtração
  3. 3
    ExplicaçãoSepare throw da declaração
  4. 4
    DesafioEscolha a falha padrão adequada
  5. 5
    ConexãoUma sobrescrita mantém as promessas aos chamadores
  6. 6
    ExemploDê ao estoque insuficiente seu próprio tipo
  7. 7
    ExemploMantenha a solicitação malsucedida separada
  8. 8
    DesafioDecida qual estado permanece
  9. 9
    ExplicaçãoPreserve a falha de conversão original
  10. 10
    DesafioPasse uma falha de arquivo por um método com restrições
  11. 11
    RecapitulaçãoProjete uma exceção que o chamador possa usar
4

Abra o texto correto e feche-o com segurança

12 passos
Resolva um caminho, compatibilize as convenções de texto e acompanhe a abertura e o fechamento de recursos e falhas concorrentes.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoLocalização e tempo de vida são importantes
  2. 2
    ExemploResolva a partir do diretório de trabalho
  3. 3
    ExplicaçãoDecodifique com a codificação usada na gravação
  4. 4
    DicaRemova um terminador de linha completo
  5. 5
    DesafioFaça um decimal sobreviver ao ciclo de gravação e leitura
  6. 6
    ExplicaçãoDeclare um recurso para fechar
  7. 7
    ConexãoUse o contrato de fechamento
  8. 8
    ExemploInverta a ordem de abertura
  9. 9
    DesafioAcompanhe uma segunda abertura malsucedida
  10. 10
    Ideia-chaveMantenha uma falha do corpo como a principal informada
  11. 11
    DesafioSepare a falha de dados da falha de limpeza
  12. 12
    RecapitulaçãoExamine uma operação de arquivo em ordem
5

Transforme leituras em um relatório confiável

16 passos
Leia e valide registros simples, calcule os resultados aceitos e salve a saída concluída com uma política clara de falhas.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoUm relatório precisa de mais que cálculos corretos
  2. 2
    ExplicaçãoEscolha como as linhas serão recebidas
  3. 3
    ExemploDefina o registro antes da análise e conversão
  4. 4
    ExemploValide antes de usar o segundo campo
  5. 5
    DesafioLocalize o registro rejeitado
  6. 6
    ExplicaçãoEscolha entre substituir e acrescentar ao final
  7. 7
    ExemploGrave uma linha de relatório portátil
  8. 8
    DicaIdentifique uma gravação malsucedida
  9. 9
    DesafioMantenha os registros antigos e novos
  10. 10
    ConexãoRecupere a execução em dois níveis diferentes
  11. 11
    ExemploAtualize os totais somente após a validação
  12. 12
    DesafioTrate um valor que é convertido, mas não serve
  13. 13
    ExplicaçãoConclua a saída antes de substituir o destino
  14. 14
    DicaMantenha visível a falha de salvamento
  15. 15
    DesafioEscolha o que pode ser informado com segurança
  16. 16
    RecapitulaçãoRevise o processador por caminho de falha

Questões de Exceções em Java

40 Questões de Prática em 4 conjuntos

Conjunto 1: Acompanhe falhas e escolha uma recuperação útil10 Questões de Prática

Questão 1 de 10

DataProblem estende Exception diretamente. Qual obrigação um método tem ao chamar um método auxiliar declarado com throws DataProblem?
  1. Capturar RuntimeException ou declará-la.
  2. Declará-la apenas se o método auxiliar falhar.
  3. Tratá-la apenas durante a execução do programa.
  4. Capturar DataProblem ou declará-la.
Mostrar respostaOcultar resposta
Resposta: D
DataProblem é verificada porque estende Exception fora do ramo de RuntimeException. O código chamador deve capturá-la ou declarar um tipo verificado aplicável. O compilador verifica a possibilidade declarada, mesmo que uma chamada específica seja bem-sucedida.

Questão 2 de 10

Um vetor tem comprimento 5. O que acontece quando o programa avalia values[5]?
  1. Ele lê o quinto elemento do vetor.
  2. Ele lança ArrayIndexOutOfBoundsException.
  3. Ele retorna o valor inteiro padrão 0.
  4. Ele lança NumberFormatException.
Mostrar respostaOcultar resposta
Resposta: B
Um vetor de comprimento 5 tem índices válidos de 0 a 4, portanto o índice 5 está fora dele. Java lança ArrayIndexOutOfBoundsException nesse acesso. Contar cinco elementos não torna o índice 5 válido: o quinto elemento está no índice 4.

Questão 3 de 10

Quais letras são exibidas, em ordem?

System.out.print("P");
try {
    int n = Integer.parseInt("7q");
    System.out.print("Q");
} catch (NumberFormatException e) {
    System.out.print("R");
}
System.out.print("S");
  1. PRS
  2. PQRS
  3. PR
  4. PS
Mostrar respostaOcultar resposta
Resposta: A
Converter “7q” lança NumberFormatException antes da instrução que exibe Q. O tratador compatível exibe R, depois a execução continua após a instrução e exibe S. A instrução ignorada não é executada após a recuperação, portanto PQRS não pode ser a saída.

Questão 4 de 10

Um bloco pode lançar NoSuchFileException ou outra IOException. Qual ordem de captura dá a cada uma sua própria resposta?
  1. IOException, depois NoSuchFileException.
  2. Exception, depois NoSuchFileException.
  3. NoSuchFileException, depois IOException.
  4. IOException | NoSuchFileException em uma cláusula.
Mostrar respostaOcultar resposta
Resposta: C
NoSuchFileException estende IOException, portanto seu tratador específico deve aparecer primeiro. Colocar IOException primeiro já capturaria toda exceção de arquivo ausente e tornaria o tratador posterior inalcançável. Uma captura múltipla também não pode combinar esses tipos relacionados.

Questão 5 de 10

O que a chamada de pick() exibe e retorna?

static int pick() {
    try {
        return 8;
    } finally {
        System.out.print("done");
    }
}
  1. Ela retorna 8 sem exibir nada.
  2. Ela exibe done e retorna 8.
  3. Ela exibe done e não retorna valor.
  4. Ela exibe 8 e depois retorna done.
Mostrar respostaOcultar resposta
Resposta: B
A expressão de retorno é avaliada, mas o método executa finally antes de entregar esse valor ao chamador. Portanto, ele exibe done e retorna 8. Um retorno dentro de try não ignora a limpeza; somente uma transferência de controle concorrente da limpeza substituiria esse resultado.

Questão 6 de 10

Um método rejeita uma capacidade negativa antes de atribuí-la a um campo. Qual exceção padrão descreve melhor o argumento inválido?
  1. IllegalArgumentException
  2. IllegalStateException
  3. NumberFormatException
  4. UnsupportedOperationException
Mostrar respostaOcultar resposta
Resposta: A
Uma capacidade negativa viola a regra de argumento do método, portanto IllegalArgumentException descreve a falha. IllegalStateException descreveria uma chamada proibida pelo estado atual do objeto. Nenhuma operação de análise e conversão é mencionada, portanto um argumento numérico, por si só, não faz disso uma falha de formato numérico.

Questão 7 de 10

Um programa é iniciado com o diretório de trabalho /work/app. Ele cria Path.of("data", "levels.txt"). Qual localização absoluta esse caminho relativo identifica?
  1. /work/data/levels.txt
  2. /data/levels.txt
  3. /work/app/src/data/levels.txt
  4. /work/app/data/levels.txt
Mostrar respostaOcultar resposta
Resposta: D
Um caminho relativo parte do diretório de trabalho, portanto os dois elementos do caminho estendem /work/app para /work/app/data/levels.txt. Java não insere uma pasta de código-fonte. Colocar o arquivo ao lado do código-fonte só funcionaria se essa fosse a localização indicada pelo caminho resolvido.

Questão 8 de 10

O recurso a é aberto, mas a abertura do recurso b lança uma exceção. Ambos são declarados no mesmo cabeçalho de try-with-resources, nessa ordem. O fechamento de a também lança uma exceção. Qual falha chega ao chamador?
  1. A falha de fechamento, com a falha de abertura suprimida.
  2. A falha de abertura, com a falha de fechamento descartada.
  3. A falha de abertura, com a falha de fechamento suprimida.
  4. As duas falhas separadamente, em sua ordem de ocorrência.
Mostrar respostaOcultar resposta
Resposta: C
Quando a abertura de b falha, Java ainda fecha a, que já está aberto. A falha de abertura permanece como principal, e a falha posterior de fechamento é associada como suprimida. Escolher a falha de fechamento como principal confunde try-with-resources com a limpeza manual que pode sobrescrever uma falha anterior.

Questão 9 de 10

Um BufferedReader chegou ao fim de seu arquivo. O que a próxima chamada de readLine() retorna?
  1. null
  2. Uma cadeia de caracteres vazia.
  3. Uma cadeia de caracteres contendo "EOF".
  4. Uma cadeia de caracteres contendo "\n".
Mostrar respostaOcultar resposta
Resposta: A
BufferedReader.readLine() retorna null quando não restam caracteres para formar outra linha. Uma cadeia vazia representa uma linha em branco real, portanto usá-la como marcador de fim interromperia a leitura cedo demais. Terminadores de linha são removidos das linhas retornadas e não são marcadores de fim de arquivo.

Questão 10 de 10

Um arquivo de registro UTF-8 pode já existir ou estar ausente. Quais opções permitem que Files.writeString preserve o texto existente e adicione novo texto ao final?
  1. CREATE e TRUNCATE_EXISTING
  2. CREATE e APPEND
  3. APPEND sem CREATE
  4. CREATE_NEW e WRITE
Mostrar respostaOcultar resposta
Resposta: B
APPEND grava após o conteúdo existente, e CREATE permite criar um arquivo ausente. Usar apenas APPEND falha quando o arquivo de registro não existe. TRUNCATE_EXISTING apagaria o conteúdo existente, enquanto CREATE_NEW rejeita um caminho que já existe.
Conjunto 2: Aplique contratos a registros e à saída de arquivos10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Um rastreamento começa com estes registros de ativação. Qual linha na classe do aluno deve ser examinada primeiro?

java.lang.NumberFormatException: For input string: "six"
    at java.base/java.lang.NumberFormatException.forInputString(...)
    at java.base/java.lang.Integer.parseInt(...)
    at Importer.readCount(Importer.java:18)
    at Importer.main(Importer.java:6)
  1. A linha 6 em Importer.main.
  2. O registro da biblioteca em forInputString.
  3. A linha 18 em Importer.readCount.
  4. A linha após a linha 18 em Importer.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

AmountProblem estende IllegalArgumentException. Como ela é classificada?
  1. Não verificada, por meio de RuntimeException.
  2. Verificada, porque é uma classe personalizada.
  3. Verificada, porque sua classe pai é uma exceção.
  4. Não verificada, por meio do ramo de Error.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Um laço de repetição captura InputMismatchException de Scanner.nextInt(), exibe uma mensagem e chama nextInt() novamente de imediato. A próxima unidade de entrada é “muitos”. Por que o laço continua falhando?
  1. O tratador rebobina todo o fluxo de entrada.
  2. O scanner converte a unidade de entrada em zero.
  3. A exceção fecha o scanner permanentemente.
  4. A leitura malsucedida deixa a mesma unidade sem ser lida.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Uma interface declara void load() throws IOException. Uma implementação precisa declarar uma falha de arquivo ausente. Qual declaração verificada é permitida em sua sobrescrita?
  1. throws Exception
  2. throws NoSuchFileException
  3. throws Throwable
  4. throws InterruptedException
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Um estoque contém 17 marcadores. Seu método remove rejeita solicitações maiores que o estoque atual antes de alterar o mapa. Chamadas removem 6 e depois solicitam 14; a segunda falha é encapsulada com sua causa e capturada pelo chamador. Que estoque e informações de diagnóstico permanecem?
  1. 11 marcadores, mas apenas a nova mensagem do encapsulador.
  2. -3 marcadores e a falha original como causa.
  3. 11 marcadores e a falha original como causa.
  4. 17 marcadores e a falha original como causa.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

O que acontece quando Double.parseDouble("6,25") é executado em um computador que usa configurações regionais alemãs?
  1. Ele retorna o valor decimal 6,25.
  2. Ele retorna o valor inteiro 625.
  3. Ele lança MalformedInputException.
  4. Ele lança NumberFormatException.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Qual interface um objeto deve implementar para ser declarado como recurso de try-with-resources?
  1. AutoCloseable
  2. Serializable
  3. Iterable
  4. Comparable
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

A linha é “Nora,”. Qual diferença é relevante entre line.split(",") e line.split(",", -1)?
  1. Ambos retornam dois campos, com o segundo vazio.
  2. O primeiro mantém a vírgula; o segundo a remove.
  3. O primeiro retorna um campo; o segundo mantém um segundo campo vazio.
  4. O primeiro lança uma exceção; o segundo retorna um campo.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Um programa grava por meio de PrintWriter, mas um disco cheio impede que o texto seja salvo. O que ele deve usar para detectar o erro registrado pelo gravador?
  1. Capturar IOException do próprio println.
  2. Chamar checkError() e examinar o resultado.
  3. Examinar o getFileName() do caminho do arquivo.
  4. Supor que o fechamento garante o salvamento.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Um relatório deve proteger um resultado existente contra substituição parcial. A leitura e o cálculo terminaram. Qual política de salvamento é adequada?
  1. Gravar diretamente no destino; tentar novamente desde o início se a primeira gravação falhar.
  2. Gravar um arquivo temporário; usar uma movimentação não atômica se a atômica falhar.
  3. Verificar se o destino existe; acrescentar o novo relatório após o resultado antigo.
  4. Gravar e fechar um arquivo temporário na mesma pasta; solicitar uma movimentação atômica e informar uma substituição não suportada.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 3: Acompanhe falhas que interagem e a limpeza10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Qual valor é exibido?

int count;
try {
    count = Integer.parseInt("bad");
} catch (NumberFormatException e) {
    count = 4;
}
System.out.println(count + 2);
  1. 4
  2. 2
  3. 6
  4. Nada; count não está inicializada.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Qual família de exceções também recebe NumberFormatException quando capturada por um tratador de superclasse?
  1. RuntimeException
  2. IOException
  3. Error
  4. FileNotFoundException
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Qual valor chega à instrução final de impressão?

int total = 0;
try {
    for (String text : new String[] {"8", "bad", "3"}) {
        try {
            total += Integer.parseInt(text);
        } catch (NumberFormatException e) {
            throw new IllegalStateException("record", e);
        }
    }
} catch (IllegalStateException e) {
    total += 2;
}
System.out.println(total);
  1. 13
  2. 10
  3. 11
  4. 2
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

O que result() faz?

static int result() {
    try {
        throw new IllegalArgumentException("bad");
    } finally {
        return 9;
    }
}
  1. Lança a exceção e nunca retorna 9.
  2. Retorna 9 e depois lança a exceção ao chamador.
  3. Não compila porque finally não pode retornar.
  4. Retorna 9 e descarta a exceção pendente.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Um analisador captura NumberFormatException e. Sua InvalidRecordException personalizada tem construtores que recebem apenas uma mensagem ou uma mensagem e uma causa. Como ele deve adicionar “Line 8” preservando o rastreamento original?
  1. throw new InvalidRecordException(e.getMessage());
  2. throw new InvalidRecordException("Line 8", e);
  3. throw new InvalidRecordException("Line 8");
  4. throw new RuntimeException("Line 8");
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Um arquivo de texto do Windows contém linhas de inteiros terminadas por CRLF. O código usa Files.readString(path).split("\n") e depois Integer.parseInt em cada trecho não vazio. Por que a conversão de um trecho que contém os algarismos “27” pode falhar?
  1. parseInt sempre exige um ponto decimal.
  2. UTF-8 não consegue representar terminadores de linha do Windows.
  3. A divisão pode deixar um \r no final do trecho.
  4. A divisão transforma automaticamente os algarismos em bytes.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Os recursos a e b são abertos com sucesso nessa ordem. O corpo lança E; o fechamento de b lança F; o fechamento de a lança G. O que chega ao catch associado a essa instrução try-with-resources?
  1. E, com F e depois G como falhas suprimidas.
  2. G, com E e depois F como falhas suprimidas.
  3. F, com G e depois E como falhas suprimidas.
  4. Apenas E, pois o fechamento para após F.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Um pequeno arquivo começa com “name,age”, seguido de “Omar,36”. Por que a primeira linha deve ser tratada separadamente antes da conversão do campo de idade?
  1. Ela usa uma codificação de caracteres diferente dos dados.
  2. Sua vírgula impede split de encontrar dois campos.
  3. Um leitor a retorna automaticamente como uma linha vazia.
  4. Ela nomeia as colunas em vez de fornecer uma idade inteira.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Um processador lê “zone,temperature” como cabeçalho e depois “north,2.0”, “east,bad” e “west,8.0”. A regra exigida é ignorar registros inválidos e salvar um relatório dos válidos. Atualmente, um catch envolve todo o laço de análise e conversão. Qual alteração atende à regra?
  1. Manter o catch fora; retomar o laço automaticamente após o tratador.
  2. Gravar cada total no destino antes de tentar converter o próximo registro.
  3. Capturar falhas de registro em cada iteração; salvar só após concluir a leitura e o cálculo.
  4. Retornar um resultado vazio do leitor sempre que a análise e conversão falharem.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

A entrada é verificada com Files.exists e depois lida com um scanner. Seu laço termina após apenas alguns registros porque o leitor subjacente falhou, e o programa começa a salvar imediatamente. O que deve mudar para impedir que essa entrada parcial seja tratada como sucesso?
  1. Verificar ioException() após a leitura e interromper o salvamento quando houver uma falha registrada.
  2. Repetir Files.exists após a leitura e salvar sempre que retornar true.
  3. Capturar apenas NumberFormatException em cada leitura e depois salvar.
  4. Fechar o scanner e supor que suas leituras anteriores completaram o arquivo.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 4: Diagnostique e melhore um processador completo10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

O que é exibido antes de a exceção sair de main, e qual é o primeiro registro de ativação da aplicação em seu rastreamento?

public class Counter {
    static int read() {
        return Integer.parseInt("9z");
    }
    static void show() {
        System.out.print("L");
        System.out.print(read());
        System.out.print("M");
    }
    public static void main(String[] args) {
        show();
        System.out.print("N");
    }
}
  1. LM; Counter.show(Counter.java:7).
  2. Apenas L; Counter.main(Counter.java:11).
  3. LMN; Counter.read(Counter.java:3).
  4. Apenas L; Counter.read(Counter.java:3).
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Um bloco catch informa uma entrada numérica inválida, mas continua com um valor padrão atribuído anteriormente. O que deve ser verdadeiro sobre esse valor para que a recuperação seja útil?
  1. Ele deve ser sempre o valor inteiro zero.
  2. Ele deve ser um valor válido para o restante do cálculo.
  3. Ele deve ser igual ao texto cuja conversão falhou.
  4. Ele deve ser atribuído dentro da instrução que falhou.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Um analisador usa catch (NumberFormatException | IllegalArgumentException e). Por que essa captura múltipla não compila?
  1. Nenhuma das alternativas é uma exceção verificada.
  2. As alternativas exigem dois nomes de variável diferentes.
  3. Uma alternativa é subclasse da outra.
  4. A captura múltipla permite apenas falhas relacionadas a arquivos.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

O que choose() exibe e retorna?

static int choose() {
    int value = 5;
    try {
        return value;
    } finally {
        value = 12;
        System.out.print(value);
    }
}
  1. Exibe 12 e retorna 5.
  2. Exibe 12 e retorna 12.
  3. Exibe 5 e retorna 5.
  4. Não exibe nada e retorna 12.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

A interface ReaderTask declara String read() throws IOException. A classe FixedTask a implementa com public String read() e sem declaração de exceção verificada. A variável task tem tipo ReaderTask e se refere a um FixedTask. O que o código que chama task.read() deve fazer?
  1. Omitir o tratamento porque a implementação não declara falha verificada.
  2. Capturar RuntimeException em vez do tipo verificado declarado.
  3. Adicionar throws IOException à implementação antes de chamá-la.
  4. Capturar ou declarar IOException conforme a declaração da interface.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Um método que sobrescreve outro não pode adicionar exceções verificadas, mas chama código de arquivo que pode lançar IOException. Qual encapsulador padrão preserva essa causa e apresenta uma falha não verificada?
  1. new IOException(e.getMessage())
  2. new UncheckedIOException(e)
  3. new Exception(e)
  4. new RuntimeException("error")
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

O corpo de uma instrução com recurso retorna 6. Seu close() então lança IOException, e o catch associado retorna 2; seu bloco finally exibe “closed” sem lançar uma exceção. O que o método faz?
  1. Exibe closed e retorna 2.
  2. Exibe closed e retorna 6.
  3. Lança IOException e não retorna valor.
  4. Retorna 6 sem entrar no catch.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Um arquivo tem o cabeçalho “label,count”, seguido de “oak,7”, “ash,”, “elm,11” e “fir,x”. O processador ignora o cabeçalho, preserva campos vazios na divisão, valida ambos os campos e captura falhas de registro dentro do laço. Quais são a contagem válida, a soma e os números das linhas físicas rejeitadas?
  1. 3 registros, soma 18; rejeita apenas a linha 5.
  2. 1 registro, soma 7; rejeita as linhas 3, 4 e 5.
  3. 2 registros, soma 18; rejeita as linhas 3 e 5.
  4. 2 registros, soma 18; rejeita as linhas 2 e 4.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Um arquivo de dados UTF-8 deve conter uma linha “sample,7.50”, cujo segundo campo possa ser lido com Double.parseDouble em computadores com qualquer configuração regional. Qual abordagem de gravação atende a esse formato?
  1. Gravar "sample," + String.format("%.2f", 7.5) e um terminador de linha.
  2. Gravar "sample," + String.format(Locale.ROOT, "%.2f", 7.5) e um terminador de linha.
  3. Gravar "sample," + String.format(Locale.GERMANY, "%.2f", 7.5) e um terminador de linha.
  4. Gravar "sample," + Integer.toString((int) 7.5) e um terminador de linha.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Um processador lê um cabeçalho válido e três registros inválidos. Ele deve informar os dados aceitos e os registros ignorados e proteger um relatório existente contra substituição parcial. Qual resultado e sequência de salvamento são adequados?
  1. Informar nenhuma leitura válida e três registros ignorados; mover a saída temporária para o destino antes de fechar seu gravador.
  2. Informar nenhuma leitura válida e quatro registros ignorados; fechar a saída temporária e solicitar substituição atômica.
  3. Informar nenhuma leitura válida e três registros ignorados; substituir o destino diretamente, depois descarregar o buffer e fechar o gravador.
  4. Informar nenhuma leitura válida e três registros ignorados; fechar a saída temporária e solicitar substituição atômica.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Travou em uma questão sua? Ajuda com Tarefas

Termos-Chave

64 Termos-Chave, cada um com sua definição

A

Acréscimo ao final do arquivo
O acréscimo ao final do arquivo adiciona nova saída ao fim de um arquivo existente enquanto preserva os caracteres já armazenados nele.
Acrescentar uma entrada a um arquivo de registro preserva as anteriores, mas não insere um separador ausente antes do novo texto.
Análise e conversão de texto
A análise e conversão de texto interpreta o texto conforme uma estrutura esperada, convertendo campos em valores ou objetos que o programa pode usar.
A análise e conversão de um registro de nome e idade verifica seus dois campos antes de converter a idade e construir uma pessoa.
Arquivo temporário
Um arquivo temporário mantém uma saída intermediária separada do destino final para que ela possa ser concluída antes de uma tentativa de substituição.
Um arquivo temporário para um relatório é criado na pasta de destino antes que o texto concluído seja movido para o local final.

B

Bloco finally
Um bloco finally é um código de limpeza executado quando o controle sai de sua instrução try, inclusive após o trabalho normal, um tratador, um retorno ou uma exceção lançada.
O bloco finally exibe uma mensagem de limpeza antes que um valor preparado por return chegue ao chamador.
Bloco try
Um bloco try contém trabalho cujas exceções podem ser tratadas por cláusulas catch associadas; suas instruções restantes são ignoradas em caso de falha.
Um bloco try que converte texto em um inteiro e depois o imprime para antes da instrução de impressão quando a conversão falha.

C

Caminho absoluto
Um caminho absoluto especifica uma localização a partir da raiz do sistema de arquivos, incluindo a raiz de uma unidade quando necessário, independentemente do diretório de trabalho.
Chamar toAbsolutePath() mostra o caminho absoluto usado para diagnosticar um arquivo colocado na pasta errada.
Caminho relativo
Um caminho relativo identifica uma localização a partir do diretório de trabalho, em vez de começar na raiz do sistema de arquivos ou de uma unidade.
O caminho relativo data/counts.txt pode identificar um arquivo diferente quando o programa é iniciado em outra pasta.
Campo
Um campo é um valor dentro de um registro estruturado, como o nome ou a idade separados por vírgula em uma linha simples de dados de texto.
O segundo campo em “Mina,” está vazio quando a divisão usa um limite negativo que preserva os campos vazios no final.
Captura múltipla
Uma captura múltipla é uma cláusula catch que une tipos de exceção sem relação de herança com uma barra vertical para que compartilhem o mesmo corpo de tratamento.
Uma captura múltipla pode informar um registro malformado tanto para um campo inteiro inválido quanto para um elemento ausente de um vetor.
Causa
Uma causa é o objeto lançável original preservado dentro de uma exceção encapsuladora e disponível por meio de getCause para diagnóstico.
A causa de uma InvalidRecordException pode ser a NumberFormatException lançada por seu campo numérico.
Classe BufferedReader
Um BufferedReader lê entrada de caracteres com eficiência usando um buffer e pode retornar uma linha por vez sem seu terminador.
Um laço com BufferedReader processa uma entrada grande até que readLine() retorne null no final.
Classe BufferedWriter
Um BufferedWriter grava saída de caracteres por meio de um buffer, oferece suporte a terminadores de linha e informa falhas de entrada e saída com IOException.
Um BufferedWriter grava uma linha de relatório e depois usa newLine() para adicionar o terminador de linha da plataforma.
Classe Error
Um Error é um subtipo de Throwable para falhas graves de execução ou do ambiente que o tratamento comum de uma aplicação não deve tentar capturar.
OutOfMemoryError pertence a Error; capturar entradas inválidas comuns não resolve o esgotamento do heap.
Classe PrintWriter
Um PrintWriter grava saída formatada de caracteres com métodos de impressão que registram falhas de entrada e saída internamente para que checkError as informe.
Um PrintWriter pode formatar uma média com printf, mas o retorno bem-sucedido dessa chamada não prova que o salvamento teve sucesso.
Classe RuntimeException
RuntimeException é a subclasse de Exception cujas descendentes representam falhas não verificadas, incluindo argumentos inválidos e uso de referência nula.
NumberFormatException chega a RuntimeException por meio de sua superclasse IllegalArgumentException.
Classe Scanner
Um Scanner lê texto como unidades de entrada ou linhas e oferece métodos de conversão, além de registrar falhas subjacentes de leitura para exame posterior.
Um Scanner de arquivo precisa de uma verificação de ioException() após seu laço para que uma leitura malsucedida não pareça bem-sucedida.
Classe Throwable
Throwable é a superclasse Java dos objetos que podem ser lançados, com Error e Exception como suas duas principais subclasses diretas.
Uma exceção verificada personalizada pertence a Throwable por meio de Exception, portanto Java pode lançá-la e capturá-la.
Cláusula catch
Uma cláusula catch indica um tipo que pode ser lançado e um tratador executado quando uma exceção do trabalho protegido corresponde a esse tipo.
Uma cláusula catch para NumberFormatException pode pedir outro número depois que o usuário digitar “muitos”.
Cláusula throws
Uma cláusula throws é parte da declaração de um método que lista tipos de exceção que podem sair dele e passa aos chamadores as obrigações de tratamento de exceções verificadas.
A cláusula throws throws IOException permite que um método auxiliar de arquivo informe a falha a um chamador capaz de se recuperar.
Codificação de caracteres
Uma codificação de caracteres associa caracteres de texto a bytes armazenados e especifica como um leitor interpreta esses bytes novamente como texto.
Uma codificação de caracteres incompatível pode exibir o texto UTF-8 “café” como texto corrompido, por exemplo, “café”.
Configuração regional
Uma configuração regional fornece convenções de idioma e formatação regional que podem afetar a análise e conversão de números pelo scanner e a saída decimal formatada.
Selecionar a configuração regional raiz faz com que os dados decimais formatados usem “3.50” independentemente das configurações do computador.

D

Descarga do buffer
A descarga do buffer envia a saída que aguarda no buffer de um gravador para seu destino; ela não libera, por si só, o recurso aberto.
A descarga faz o texto pendente sair do buffer do gravador, mas o programa ainda deve fechar seu recurso de arquivo.
Diretório de trabalho
O diretório de trabalho é a pasta atual do programa usada como ponto de partida para caminhos relativos, que pode ser diferente da pasta do código-fonte.
Com /work/app como diretório de trabalho, data/counts.txt aponta para dentro de /work/app/data.

E

Encadeamento de exceções
O encadeamento de exceções preserva uma exceção original como causa de uma nova exceção que acrescenta um tipo ou contexto de diagnóstico mais útil.
O encadeamento de exceções acrescenta o número da linha do registro que falhou sem perder o rastreamento original da conversão.
Exceção
Uma exceção é um objeto que descreve um evento que interrompe um programa em execução e transfere o controle em direção a um tratador compatível.
Uma exceção na análise e conversão de “vermelho” interrompe a atribuição antes que o programa possa usar seu resultado numérico.
Exceção ArithmeticException
Uma ArithmeticException é uma exceção não verificada que indica uma condição aritmética excepcional, como a divisão inteira por zero.
Calcular uma média inteira com um vetor vazio pode lançar ArithmeticException na divisão.
Exceção IllegalArgumentException
Uma IllegalArgumentException é uma exceção não verificada usada quando um chamador fornece um valor que viola os requisitos de argumento de um método.
Um método pode lançar IllegalArgumentException quando sua quantidade obrigatoriamente positiva é fornecida como -2.
Exceção IllegalStateException
Uma IllegalStateException é uma exceção não verificada usada quando o estado atual de um objeto não permite a operação solicitada.
Um pedido já enviado pode lançar IllegalStateException quando o código tenta adicionar outro item a ele.
Exceção InputMismatchException
Uma InputMismatchException é uma falha não verificada do scanner quando uma unidade de entrada não corresponde ao tipo ou intervalo solicitado por um método de conversão.
nextInt() lança InputMismatchException ao encontrar “vários” e deixa essa unidade de entrada disponível para ser descartada.
Exceção não verificada
Uma exceção não verificada pertence a RuntimeException ou Error, ou a uma subclasse de um desses tipos, e não está sujeita à exigência obrigatória de capturar ou declarar.
Um índice de vetor incorreto causa uma exceção não verificada mesmo quando o programa foi compilado com sucesso.
Exceção NullPointerException
Uma NullPointerException é uma exceção não verificada lançada quando uma operação exige um objeto, mas recebe ou usa uma referência nula.
Chamar name.trim() quando name é null lança NullPointerException antes que qualquer texto sem espaços ao redor seja retornado.
Exceção NumberFormatException
Uma NumberFormatException é uma exceção não verificada lançada quando a conversão de texto numérico não consegue produzir o valor numérico solicitado.
Integer.parseInt("blue") lança NumberFormatException porque o texto não pode representar um inteiro.
Exceção personalizada
Uma exceção personalizada é uma classe definida pela aplicação cujos objetos podem ser lançados e que permite aos chamadores reconhecer e tratar uma falha significativa do domínio.
Um estoque usa uma exceção personalizada para distinguir estoque insuficiente de um argumento inválido.
Exceção suprimida
Uma exceção suprimida é uma falha adicional associada a uma exceção principal, como uma falha de fechamento depois que o corpo de um recurso já lançou uma exceção.
A exceção suprimida preserva uma falha de fechamento do leitor enquanto a falha original de análise e conversão se propaga.
Exceção UncheckedIOException
Uma UncheckedIOException é uma subclasse padrão de RuntimeException que encapsula uma IOException e preserva a falha original de arquivo como sua causa.
Um método que sobrescreve outro e não pode declarar IOException pode repassar uma falha de arquivo usando UncheckedIOException.
Exceção verificada
Uma exceção verificada é um subtipo de Throwable fora dos ramos de RuntimeException e Error que exige tratamento pela regra de capturar ou declarar.
Uma IOException é uma exceção verificada, portanto um método auxiliar de leitura de arquivos deve capturá-la ou declará-la.

F

Falha em um registro
Uma falha em um registro torna um registro de entrada inutilizável, mas permite que registros posteriores sejam processados sob uma regra de ignorar e informar.
Uma falha em um registro informa “Linha 6: temperatura inválida” e deixa a próxima iteração alcançável.
Falha imediata
Falha imediata significa rejeitar uma entrada ou um estado inválido no ponto em que é detectado, antes que o trabalho posterior possa espalhar ou obscurecer o problema.
A falha imediata em um método modificador verifica uma porcentagem inválida antes de atribuir qualquer valor ao campo.
Falha no processamento do arquivo inteiro
Uma falha no processamento do arquivo inteiro impede que uma operação de arquivo seja concluída de forma confiável, como uma entrada ausente ou um erro de disco ao salvar um relatório.
Uma falha no processamento do arquivo inteiro durante a leitura deve interromper o salvamento para que uma entrada incompleta não seja informada como resultado completo.

H

Hierarquia de exceções
Uma hierarquia de exceções é uma estrutura de herança que permite aos chamadores capturar uma falha específica ou uma superclasse comum de falhas relacionadas.
Uma hierarquia de exceções pode colocar falhas de item desconhecido e estoque insuficiente sob um mesmo tipo base de estoque.

I

Instrução try com recursos
A instrução try com recursos é uma instrução Java que fecha automaticamente recursos AutoCloseable abertos com sucesso quando o trabalho protegido é encerrado.
Try-with-resources fecha um gravador antes do leitor quando as declarações no cabeçalho abrem o leitor primeiro.
Interface AutoCloseable
AutoCloseable é a interface que declara close e torna um objeto elegível para fechamento automático por uma instrução try-with-resources.
Uma classe auxiliar que implementa AutoCloseable pode exibir seu nome quando a limpeza automática chama close().
Interface Closeable
Closeable é uma subinterface de AutoCloseable para recursos de entrada e saída cujo método close declara IOException em vez da Exception mais abrangente.
Um BufferedReader implementa Closeable, portanto pode ser declarado em try-with-resources.
Interface Path
Um Path é um objeto que representa uma localização em um sistema de arquivos; construí-lo não abre, cria nem verifica o arquivo indicado.
Path.of("data", "counts.txt") constrói um Path sem testar se a pasta de dados existe.

L

Limpeza
Limpeza é o trabalho que libera recursos ou restaura uma configuração quando uma operação termina, inclusive em caminhos que saem devido a uma falha.
A limpeza fecha um arquivo aberto mesmo quando a conversão de um de seus registros lança uma exceção.
Linha de cabeçalho
Uma linha de cabeçalho nomeia as colunas em um arquivo de dados e é tratada separadamente para que seus rótulos não sejam analisados e convertidos como valores de registros comuns.
A linha de cabeçalho “name,age” deve ser ignorada ou verificada antes que o analisador tente converter uma idade.

M

Mascaramento de exceção
O mascaramento de exceção ocorre quando uma transferência de controle posterior substitui uma falha anterior, ocultando a exceção original do chamador.
Um retorno em finally pode causar mascaramento de exceção ao descartar uma falha lançada no bloco try.
Memória intermediária
Uma memória intermediária é uma área de memória que mantém texto temporariamente antes de enviá-lo a um arquivo, reduzindo muitas pequenas operações de saída.
O buffer de um gravador ainda pode conter a última linha do relatório até ser descarregado ou até o gravador ser fechado.
Movimentação atômica
Uma movimentação atômica altera a localização de um arquivo em uma única operação do sistema de arquivos, quando suportada; a substituição de um destino existente depende da implementação.
Uma movimentação atômica disponibiliza um relatório concluído de uma só vez, e uma substituição não suportada é informada como falha de salvamento.

O

Ordem das cláusulas catch
A ordem das cláusulas catch é a sequência de cima para baixo em que os tratadores são testados, exigindo que um tratador de subclasse preceda um de superclasse.
A ordem das cláusulas catch coloca NoSuchFileException antes de IOException quando cada uma precisa de uma mensagem separada.

P

Palavra-chave throw
A palavra-chave throw inicia uma instrução que envia um objeto de exceção para fora da operação atual e interrompe sua execução normal.
Um throw antes da atribuição ao campo rejeita uma capacidade inválida enquanto preserva o valor anterior do campo.
Pilha de chamadas
A pilha de chamadas é a cadeia de chamadas de método atualmente ativas em uma thread, cada uma aguardando o trabalho que solicitou.
Quando main chama load, que chama parse, a pilha de chamadas registra as três chamadas de método ativas.
Propagação
Propagação é a passagem de uma exceção sem tratamento para fora, pelo código que a envolve e pelos métodos chamadores, até que um tratador seja encontrado.
A propagação leva uma leitura malsucedida para fora de um método auxiliar de leitura de arquivo até um chamador que pode pedir outro arquivo.

R

Rastreamento da pilha
Um rastreamento da pilha informa uma exceção e suas chamadas de método ativas, começando pelo ponto de detecção e seguindo por seus chamadores.
Quando um método auxiliar chamado por main falha em uma conversão, o rastreamento da pilha aponta primeiro para a conversão e depois para o método auxiliar e main.
Recuperação
Recuperação é a resposta do programa que o deixa capaz de continuar de forma útil após uma falha, como tentar novamente ou ignorar um registro inválido.
A recuperação em um laço de entrada lê uma nova linha antes de tentar outra conversão, permitindo que o programa avance.
Recurso
Um recurso é um objeto que mantém acesso a algo externo, como um arquivo aberto, que deve ser liberado após o fim de seu uso.
Um leitor de arquivo é um recurso que deve ser fechado mesmo quando o processamento de sua próxima linha falha.
Região protegida
Uma região protegida é o trabalho contido em uma instrução try; seu limite determina o que é abandonado quando uma falha chega ao seu tratador.
A região protegida abrange um registro quando uma instrução try de conversão está dentro do corpo do laço.
Regra de capturar ou declarar
A regra de capturar ou declarar exige que o código capaz de lançar uma exceção verificada a trate ou liste um tipo aplicável na declaração de seu método.
A regra de capturar ou declarar aplica-se a um método que chama Files.readString, mesmo quando o arquivo que ele lê existe.
Retorno pendente
Um retorno pendente é um retorno cuja expressão já foi avaliada, mas cuja transferência ao chamador aguarda a conclusão da limpeza necessária.
Alterar um inteiro local durante finally não reavalia a expressão de um retorno pendente.

T

Terminador de linha
Um terminador de linha é a sequência de caracteres que encerra uma linha de texto, geralmente LF no Linux e no macOS ou CRLF no Windows.
Um terminador de linha lido por BufferedReader.readLine() é removido antes que o método retorne o texto da linha.
Tratador inalcançável
Um tratador inalcançável é uma cláusula catch que não pode receber uma exceção porque um tratador anterior já abrange todos os tipos correspondentes.
Colocar IOException primeiro cria um tratador inalcançável se NoSuchFileException for capturada depois.
Truncamento
Truncamento remove o conteúdo de um arquivo existente quando ele é aberto para substituição, antes mesmo de a nova saída necessariamente ter sido gravada com sucesso.
O Files.writeString padrão causa truncamento, portanto uma falha posterior de gravação pode deixar um resultado incompleto.

U

UTF-8
UTF-8 é uma codificação de caracteres Unicode que usa um byte para caracteres latinos básicos e até quatro bytes para outros caracteres Unicode.
Em UTF-8, “café” ocupa cinco bytes embora contenha apenas quatro caracteres visíveis.

V

Valores separados por vírgulas
CSV é um formato de texto com valores separados por vírgulas, que geralmente armazena um registro por linha; campos entre aspas podem conter vírgulas e exigem análise adequada de CSV.
Um CSV simples contendo “Mina,28” pode ser dividido, enquanto uma vírgula entre aspas em um nome exige um analisador de CSV.

Sobre esta aula

Por StudeliRelatar um erro

Crie seus próprios Materiais de Estudo

Transforme suas anotações, slides e documentos em Guias de Estudo, Questões de Prática, Flashcards e mais 6 ferramentas.

Começar