Atualizado: 26/10/2025

Este conteúdo é original e não foi gerado por inteligência artificial.

Throw e Throws em Java

Em Java, a execução pode falhar por condições excepcionais. Em muitas situações, a própria plataforma gera a exceção, como na divisão por zero. Também existe a possibilidade de gerar uma exceção manualmente com o operador throw, além de declarar no cabeçalho de um método, por meio de throws, que ele pode gerar exceções que o método que faz a chamada precisará tratar.

Lançando exceções com o operador throw

O operador throw cria e lança um objeto de exceção. Em termos gerais, ele recebe uma instância de um tipo que representa uma exceção. A hierarquia padrão começa em Throwable e segue por Exception e Error. Muitos tipos de exceção têm construtor que aceita uma mensagem descritiva, a mesma que será retornada por getMessage() e exibida quando a exceção for mostrada no console.

Exemplo que lê um nome e lança uma exceção quando a entrada não atende a uma condição de validade:

import java.util.Scanner;

class Program {

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        System.out.print("Enter name: ");
        String name = in.nextLine();

        // se o nome tiver menos de 2 caracteres, lança uma exceção
        if (name.length() < 2) throw new Throwable("Name is too short");

        System.out.println("Hello, " + name);
    }
}

O compilador sinaliza erro ao compilar esse código, informando que a exceção do tipo Throwable não foi tratada nem declarada. Isso ocorre porque Throwable é considerado um tipo de exceção verificada. Para esse caso, é necessário tratar no próprio método com try..catch ou declarar no cabeçalho que o método pode lançar a exceção.

Exceções verificadas e não verificadas

As exceções em Java são geralmente classificadas em dois grupos. As não verificadas englobam RuntimeException e Error, bem como suas subclasses, e não exigem tratamento nem declaração com throws. As verificadas abrangem as demais subclasses de Exception e exigem tratamento ou declaração. No exemplo anterior foi usado Throwable, que o compilador trata como verificada, por isso a necessidade de tratar ou declarar. No contexto de validação de argumentos, costuma-se preferir uma exceção não verificada como IllegalArgumentException, embora o exemplo a seguir mostre primeiro a abordagem com try..catch.

Tratamento com try..catch

A parte do código que pode lançar a exceção é colocada em um bloco try. Se a condição for violada, a exceção é lançada e o fluxo é desviado para o bloco catch, onde a mensagem é exibida.

import java.util.Scanner;

class Program {

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        System.out.print("Enter name: ");
        String name = in.nextLine();

        try {
            // se o nome tiver menos de 2 caracteres, lança uma exceção
            if (name.length() < 2) throw new Throwable("Name is too short");
            System.out.println("Hello, " + name);
        }
        catch (Throwable ex) {
            System.out.println("Error: " + ex.getMessage());
        }
    }
}

Ao submeter um único caractere, a execução cai no catch e exibe a mensagem. A mesma ideia vale para qualquer trecho em que a condição de validade precise ser garantida durante a execução.

Exemplo com outro tipo de exceção

Segue um exemplo com IllegalArgumentException, adequado para indicar que um parâmetro recebido por método ou construtor é inválido. O exemplo mantém a mesma lógica, com a checagem de faixa de idade no construtor.

class Program {

    public static void main(String[] args) {

        var tom = new Person("Tom", -20);
        tom.print();
    }
}

class Person {

    private String name;
    private int age;

    Person(String name, int age) {

        if (age < 1 || age > 110) throw new IllegalArgumentException("Invalid age: " + age);
        this.name = name;
        this.age = age;
    }

    void print() { System.out.printf("Name: %s; Age: %d%n", name, age); }
}

Neste caso, IllegalArgumentException é uma exceção não verificada. O compilador não exige tratamento ou declaração para esse cenário, e a execução encerrará com erro se a condição for violada. Quando se deseja capturar a mensagem e continuar o fluxo, o tratamento pode ser feito no método que faz a chamada, como no trecho abaixo:

class Program {

    public static void main(String[] args) {

        try {
            var tom = new Person("Tom", -20);
            tom.print();
        }
        catch (IllegalArgumentException ex) {
            System.out.println(ex.getMessage());
        }
    }
}

class Person {

    private String name;
    private int age;

    Person(String name, int age) {

        if (age < 1 || age > 110) throw new IllegalArgumentException("Invalid age: " + age);
        this.name = name;
        this.age = age;
    }

    void print() { System.out.printf("Name: %s; Age: %d%n", name, age); }
}

O operador throws

Quando um método pode gerar uma exceção verificada e não realiza o tratamento local, o cabeçalho do método deve informar isso por meio de throws. A declaração é escrita após a lista de parâmetros. O método que faz a chamada decide tratar no próprio escopo ou, por sua vez, também declarar com throws.

Exemplo em que a leitura do nome lança uma exceção verificada quando a entrada não atende a uma condição de validade.

import java.util.Scanner;

class Program {

    public static void main(String[] args) {

        try {
            printName();  // esta chamada pode lançar uma exceção
        }
        catch (Throwable ex) {
            System.out.println(ex.getMessage());
        }
    }

    static void printName() throws Throwable {

        Scanner in = new Scanner(System.in);
        System.out.print("Enter name: ");
        String name = in.nextLine();

        // se o nome tiver menos de 2 caracteres, lança uma exceção
        if (name.length() < 2) throw new Throwable("Name length is insufficient: " + name.length());
        System.out.println("Hello, " + name);
    }
}

Outra estratégia possível é propagar para o método main, declarando throws também no cabeçalho dele. O código a seguir compila com sucesso e permite que a exceção chegue ao topo:

import java.util.Scanner;

class Program {

    public static void main(String[] args) throws Throwable {

        printName(); // esta chamada pode lançar uma exceção
    }

    static void printName() throws Throwable {

        Scanner in = new Scanner(System.in);
        System.out.print("Enter name: ");
        String name = in.nextLine();

        // se o nome tiver menos de 2 caracteres, lança uma exceção
        if (name.length() < 2) throw new Throwable("O comprimento do nome é insuficiente: " + name.length());
        System.out.println("Olá, " + name);
    }
}

Em ambos os exemplos, a lógica da verificação permanece igual, com a diferença de onde fica o tratamento. Quando o método chamado não trata a exceção verificada, o método que faz a chamada precisa tratá-la ou declará-la também. Vale lembrar que um método pode declarar múltiplos tipos de exceção separados por vírgula em throws. Para exceções não verificadas como IllegalArgumentException, a declaração não é obrigatória, já que o compilador não faz verificação delas.

Observação: embora os exemplos usem Throwable apenas para fins didáticos, a prática comum no desenvolvimento em Java evita lançar ou capturar esse tipo diretamente. Em validações de entrada, é comum empregar IllegalArgumentException ou criar um tipo específico de exceção de domínio quando se deseja diferenciar claramente o erro.


Resumo

  • throw lança explicitamente um objeto de exceção; a mensagem pode ser fornecida no construtor.
  • Exceções verificadas exigem tratamento com try..catch ou declaração com throws; exceções não verificadas não exigem isso.
  • IllegalArgumentException é adequada para parâmetros inválidos, enquanto Throwable não costuma ser lançada em código de aplicação.
  • throws declara no cabeçalho que o método pode lançar exceções, delegando a decisão de tratamento ao método que faz a chamada.
  • A mesma exceção pode ser tratada localmente com try..catch ou propagada; declarar vários tipos em throws é possível quando necessário.