Percursos
/
Java
Java
/
Exercícios
/
Enigma da calculadora
Enigma da calculadora

Enigma da calculadora

Exercício de aprendizagem

Introdução

Exceções

A linguagem de programação Java usa exceções para tratar erros e outros acontecimentos excecionais.

O que é uma exceção

Uma exceção é um acontecimento que ocorre durante a execução de um programa e que perturba o fluxo normal das instruções. As exceções são lançadas explicitamente em Java. Ao ato de desencadear uma exceção dá-se o nome de lançar uma exceção, e ao ato de a tratar dá-se o nome de capturar uma exceção.

Em Java, todas as exceções são subclasses da classe Exception, que por sua vez é uma subclasse de Throwable.

Java distingue dois tipos de exceções:

  1. Exceções verificadas
  2. Exceções não verificadas
Exceções verificadas

As exceções verificadas são condições excecionais que uma aplicação deve antecipar e das quais deve recuperar. Um exemplo de exceção verificada é a FileNotFoundException, que ocorre quando um método está a tentar ler um ficheiro que não existe.

Este tipo de exceção é verificado em tempo de compilação: os métodos que lançam exceções verificadas devem indicá-lo na assinatura do método, e o código que chama um método que pode lançar uma exceção verificada tem de a tratar, caso contrário o código não compila.

Todas as exceções verificadas são subclasses de Exception que não estendem RuntimeException.

Exceções não verificadas

As exceções não verificadas são condições excecionais que uma aplicação normalmente não consegue antecipar nem recuperar de. Um exemplo de exceção não verificada é a NullPointerException, que ocorre quando um método que espera um valor não nulo recebe null.

Este tipo de exceção não é verificado em tempo de compilação: os métodos que lançam exceções não verificadas não precisam de o indicar na assinatura do método, e o código que chama um método que pode lançar uma exceção não verificada não é obrigado a tratá-la.

Todas as exceções não verificadas herdam de RuntimeException, que por sua vez é uma extensão de Exception.

Lançar exceções

Um método em Java pode lançar uma exceção com a instrução throw.

Lançar uma exceção verificada

Ao lançar uma exceção verificada a partir de um método, é obrigatório indicá-lo na assinatura do método com a palavra-chave throws, como mostra o exemplo abaixo. Isto obriga o código que chama o método a antecipar que pode ser lançada uma exceção e a tratá-la em conformidade.

public class InsufficientBalanceException extends Exception {

}

public class BankAccount {
  public void withdraw(double amount) throws InsufficientBalanceException {
    if (balance < amount) {
      throw new InsufficientBalanceException();
    }

    // rest of the method implementation
  }
}
Lançar uma exceção não verificada

Ao lançar uma exceção não verificada a partir de um método, não é obrigatório indicá-lo na assinatura do método, embora seja possível.

public class BankAccount {
  public void withdraw(double amount) {
    if (amount < 0) {
      throw new IllegalArgumentException("Cannot withdraw a negative amount");
    }

    // rest of the method implementation
  }
}

Tratamento de exceções

O tratamento de exceções em Java faz-se com as palavras-chave try, catch e finally.

  • As instruções de código que podem lançar uma exceção devem ser envolvidas num bloco try.
  • O bloco try é seguido de um ou mais blocos catch, que capturam as exceções lançadas no bloco try.
  • Os blocos catch podem ser seguidos, opcionalmente, de um bloco finally, que é sempre executado depois do bloco try, independentemente de ter sido lançada ou não uma exceção.

O exemplo seguinte mostra como funcionam estas palavras-chave:

public class ATM {
  public void withdraw(BankAccount bankAccount, double amount) {
    try {
      System.out.println("Withdrawing " + amount);
      bankAccount.withdraw(amount);
      System.out.println("Withdrawal succeeded");
    } catch (InsufficientBalanceException) {
      System.out.println("Withdrawal failed: insufficient balance");
    } catch (RuntimeException e) {
      System.out.println("Withdrawal failed: " + e.getMessage());
    } finally {
      System.out.println("Current balance: " + bankAccount.getBalance());
    }
  }
}

Neste exemplo, quando não é lançada nenhuma exceção, é impresso o seguinte:

Withdrawing 10.0
Withdrawal succeeded
Current balance: 5.0

No entanto, se a instrução bankAccount.withdraw(amount) lançar uma InsufficientBalanceException, é impresso o seguinte:

Withdrawing 10.0
Withdrawal failed: insufficient balance
Current balance: 5.0

Ou, caso o bankAccount.withdraw(amount) lance uma exceção não verificada, é impresso o seguinte:

Withdrawing -10.0
Withdrawal failed: Cannot withdraw a negative amount
Current balance: 5.0

Erros

Java tem também uma categoria separada chamada erros, que são problemas graves externos a uma aplicação. Um exemplo de erro é o OutOfMemoryError, que ocorre quando uma aplicação está a tentar usar mais memória do que a disponível no sistema.

Tal como as exceções não verificadas, os erros não são verificados em tempo de compilação. A diferença é que representam problemas ao nível do sistema e são geralmente lançados pela máquina virtual Java ou pelo ambiente, e não pela aplicação. Em geral, as aplicações não devem tentar capturá-los nem tratá-los.

Todos os erros em Java herdam da classe Error.

Instruções

Neste exercício vais construir o tratamento de erros para uma calculadora simples de números inteiros. Para simplificar, são fornecidos métodos para calcular a adição, a multiplicação e a divisão.

O objetivo é teres uma calculadora a funcionar que devolva uma String com o seguinte padrão: 16 + 51 = 67, quando recebe os argumentos 16, 51 e +.

CalculatorConundrum calculator = new CalculatorConundrum();

calculator.calculate(16, 51, "+");
// => returns "16 + 51 = 67"

calculator.calculate(32, 6, "*");
// => returns "32 * 6 = 192"

calculator.calculate(512, 4, "/");
// => returns "512 / 4 = 128"

1. Implementa o método calculate para suportar algumas operações básicas

O método principal a implementar nesta tarefa é o método CalculatorConundrum.calculate(). Recebe três argumentos. Os dois primeiros argumentos, operand1 e operand2, são números inteiros sobre os quais vai ser aplicada uma operação. O terceiro argumento, operation, é do tipo String e, para este exercício, é necessário implementar as seguintes operações:

  • adição, usando a String +
  • multiplicação, usando a String *
  • divisão, usando a String /

2. Trata as operações ilegais

Atualiza o método CalculatorConundrum.calculate() para tratar operações ilegais:

  • Quando o argumento operation é null, deve ser lançada uma IllegalArgumentException com a mensagem Operation cannot be null.
  • Quando o argumento operation é "", deve ser lançada uma IllegalArgumentException com a mensagem Operation cannot be empty.
  • Quando o argumento operation é uma operação diferente de +, * ou /, deve ser lançada uma IllegalOperationException com a mensagem Operation '{operation}' does not exist.
calculator.calculate(10, 1, null);
// => throws IllegalArgumentException with message "Operation cannot be null"

calculator.calculate(10, 1, "");
// => throws IllegalArgumentException with message "Operation cannot be empty"

calculator.calculate(10, 1, "-");
// => throws IllegalOperationException with message "Operation '-' does not exist"

3. Trata a exceção lançada ao dividir por zero

Em Java, tentar dividir por zero lança uma ArithmeticException. Atualiza o método CalculatorConundrum.calculate() para apanhar esta exceção e depois lançar uma IllegalOperationException com a mensagem Division by zero is not allowed e a ArithmeticException apanhada como causa.

calculator.calculate(512, 0, "/");
// => throws IllegalOperationException with message "Division by zero is not allowed"
Editar via GitHub A ligação abre numa nova janela ou separador
Java Exercism

Estás pronto para começar Enigma da calculadora?

Inscreve-te no Exercism para aprenderes e dominares Java com 26 conceitos158 exercícios, e mentoria humana real, tudo grátis.