Objectivos

  1. Utilização de excepções para representar situações de erro num programa;
  2. Apanhar e lançar excepções;
  3. Operações de Entrada e Saída em Java: Serialização e desserialização de objectos;
  4. Praticar a compilação e execução de classes Java com packages;

Actividade

  1. Resolução do enunciado da aula;
  2. Apoio ao projecto.

Enunciado da Aula

Esta aula está dividida em três partes. A primeira tem como objectivo corrigir erros relacionados com excepções e compilar e executar código Java com packages. Na segunda parte pretende-se alterar a aplicação Jogo do Galo desenvolvida na aula de laboratório anterior por forma a utilizar o mecanismo de excepções do Java para representar situações de erro. Finalmente, a terceira parte consiste em adicionar a funcionalidade de guardar e recuperar o estado da aplicação Jogo do Galo utilizando o mecanismo de serialização do Java.

Correcção de Erros de Compilação

Veja com atenção as classes Exemplo.java e ArgumentoInvalidoException.java e tente encontrar os erros de compilação presente na classe Exemplo.

Verifique se encontrou os erros todos utilizando o compilador de java. Compile as duas classes via linha de comandos e corrija os erros encontrados. Atenção, que as duas classes não pertencem ao mesmo package. 

Execute o método main da classe Exemplo.

Representar Situações de Erro com Excepções

Na aplicação Jogo do Galo desenvolvida durante as aulas de laboratório anteriores existem algumas situações que seriam melhor modeladas utilizando o mecanismo de excepções. Pretende-se agora alterar esta aplicação por forma a representar estas situações inválidas utilizando excepções:

  • Podem acontecer duas situações de erro distintas no caso do método joga de JogoGalo a posição indicada não está livre ou a posição indicada não é válida. A melhor forma de representar estas duas situações de erro distintas é ter uma classe excepção abstracta que representa a situação abstracta de jogada inválida (representada por JogadaInvalidaException) e depois ter duas subclasses concretas desta classe que irão representar as duas situações de erro concretas, representadas por PosicaoInvalidaException e PosicaoOcupadaException;
  • Existe pelo menos ainda outra situação de erro a considerar nesta aplicação e que representa o caso em que se indica um índice inválido de um jogo do galo e que pode ocorrer no método obtemJogo de AplicacaoJogoGalo. Altere o código deste método por forma que seja lançada uma excepção em vez de devolver null sempre que se indicar um índice inválido. Deve ser criado então a classe JogoGaloInvalidoException para representar este caso.
  • Outro situação de erro que pode ser considerada é a situação de criar um jogo do galo com uma dimensão menor ou igual a 1 (não faz sentido ter um jogo do galo só com uma posição). Neste caso, a verificação da situação pode ser realizada no próprio construtor de JogoGalo, podendo ser lançada a excepção DimensaoInvalidaException.
  • Note que as várias situações de erro indicadas são representadas por uma sub-classe de Exception que normalmente tem que ser concretizada pelos programadores.
Compare a sua solução com a proposta pelo corpo docente: Guardar e Recuperar o Estado do Jogo do Galo


Altere agora a aplicação Jogo do Galo por forma a que esta seja capaz de guardar o seu estado, podendo recuperá-lo mais tarde. O estado desta aplicação é representado pelo histórico de jogos já jogados. Na concretização desta funcionalidade deverá utilizar o mecanismo de serialização/desserialização suportado pela linguagem Java. Na concretização desta funcionalidade deve:

  1. Definir bem o que constitui o estado persistente desta aplicação. Não se esqueça que as classes dos objectos que podem pertencer ao estado persistente da aplicação têm que concretizar (directa ou indirectamente a interface java.io.Serializable).
  2. Concretize o método void save(String fileName) em AplicacaoJogoGalo que deverá guardar o estado da aplicação Jogo do Galo no ficheiro com o nome referenciado por fileName. Este método deve tratar as possíveis excepções que podem acontecer no processo de serialização do estado escrevendo uma mensagem de erro no standard error (representado pelo atributo estático err de System). 
  3. Concretize um método estático AplicacaoJogoGalo load(String fileName) em AplicacaoJogoGalo que devolve uma instância da aplicação Jogo do Galo com um estado igual ao serializado anteriormente no ficheiro com o nome referenciado por fileName. A seguinte secção apresenta dois excertos de código que demonstram a aplicação do mecanismo de serialização e desserialização do Java.
  4. Acrescente a seguinte funcionalidade ao método estático main que representa o ponto de entrada da aplicação: Quando a aplicação começa, primeiro deverá recuperar o estado persistente guardado num ficheiro indicado pelo utilizador, caso seja indicado algum ficheiro, e no fim, antes de sair da aplicação, caso seja indicado algum ficheiro de saída,  a aplicação deve guardar o seu estado persistente no ficheiro indicado. Os dois ficheiros a utilizar são indicados utilizando o mecanismo de propriedades do Java. 
  5. Uma propriedade em Java é definida por um par chave-valor. Em Java é possível aceder ao valor de uma propriedade através da invocação do método estático getProperty de System, o qual recebe como argumento uma cadeia de caracteres com o nome da chave a que se quer aceder. Se a propriedade estiver definida, é devolvido o valor associado à chave em causa. Se a propriedade não estiver definida, então este método devolve null. As propriedades a utilizar para representar os ficheiros de entrada e saída devem ter como chaves input e ouputt, respectivamente. Para indicar o valor de uma propriedade deve indicar na linha de comandos (antes de colocar o nome da classe a executar) o seguinte formato -Dchave=valor.