domingo, 25 de julho de 2010

[Java] Identificar os usos adequados e inadequados de declarações


Como foi introduzido no post anterior, as declarações ou assertivas são utilizadas para verificar a validade de um programa quanto a falhas de lógica de programação e bugs. A instrução assert é utilizada para fazer a validação das declarações e não modificar o código após a verificação. Para que a instrução assert seja vericada durante a execução do código é necessária a habilitação da opção. Para executar o programa com assertivas digite: java -ea <NomeDaClasse>. A instrução assert avalia uma expressão boolean e determina se é verdadeira ou falsa.

Sintaxe da instrução assert

assert <expressão_booleana>;
assert <expressão_booleana> : &ltexpressão_de_detalhes>;

A primeira forma da sintaxe da instrução assert avalia a expressão booleana e lança um AssertionException se a mesma for false. A segunda forma da sintaxe avalia a expressão booleana e lança um AssertionExeption com a expressão de detalhes como a mensagem de erro se a expressão booleana for false.

Uso adequado de declarações

Utilizar declarações para documentar e validar a lógica interna de um único método:
  • Invariante interno

  • if (x > 0) {
    // Faz uma coisa
    } else {
    assert ( x == 0 );
    // Faz outra coisa, a não ser que x seja negativo
    }


  • Invariante de controle de fluxo

  • switch (naipe) {
    case Naipe.PAUS: // ...
    break;
    case Naipe.OUROS: // ...
    break;
    case Naipe.COPAS: // ...
    break;
    case Naipe.ESPADAS: // ...
    break;
    default: assert false : "Naipe indeterminado!!";
    break;
    }


  • Invariante de pós condição

  • public Object pop() {
    int size = this.getElementCount();
    if (size == 0) {
    throw new RuntimeException("Tentativa de retirar elemento de uma pilha vazia!");
    }

    Object result = /* Código para recuperar o elemento retirado */ ;

    // testa a pós condição
    assert (this.getElementCount() == size - 1);

    return result;
    }
Uso inadequado de declarações
  • Não utilize declarações para verificar os parâmetros de um método público. Bem como para validar parâmetros da linha de comando.

  • public void fazAlgo(int x) {
    assert (x > 0); // INAPROPRIADO!!
    // faz coisas com x
    }


    Como você não possui controle dos códigos que fazem chamada a um método público não é recomendado fazer a verificação dos parâmetros recebidos de um método público, pois a instrução assert pode ser desativada e sua verificação não mais será realizada. Ao invés de usar assert, utilize exceções!

  • Não utilize declarações que possam desencadear efeitos colaterais.

  • public void fazAlgumaCoisa() {
    assert (modificaAlgo());
    // ...
    }
    public boolean modificaAlgo() {
    y = x++;//Mudança no valor de variável
    return true;
    }


    Não é recomendado utilizar declarações que possam desencadear efeitos colaterais, pois a regra geral da utilização da instrução assert é de testar algo e deixar o código exatamente como antes do teste. Instruções assert nem sempre ocorrem, assim é impossível manter o controle do código se a instrução produzir efeistos colaterais.

quarta-feira, 21 de julho de 2010

[Java] Exceções e Declarações (Assertivas)


Exceções

Uma exceção é o evento que ocorre durante a execução de um programa que interrompe o fluxo normal das instruções. Para resolver os problemas ocorridos em uma exceção deve-se fazer o tratamento de exceção. O tratamento das exceções de um programa faz com que o mesmo fique mais robusto e tolerante às falhas. O tratamento de exceções foi projetado para processar erros síncronos (como por exemplo índice fora do intervalo do vetor, estouro aritmético, divisão por zero) e não erros assíncronos (como por exemplo chegadas de mensagens de rede, cliques do mouse), que ocorrem paralelamente com o fluxo de controle do programa e independente dele.

Tratamento de exceções

No tratamento de exceções primeiramente executa-se uma tarefa, depois se testa se a tarefa foi executada corretamente. Se não estiver sido executada corretamente, então se realiza o tratamento da exceção. Porém, mesclar o tratamento de exceções com a lógica do programa pode prejudicar a leitura do código, principalmente se o aplicativo for grande.

Declarações ou Assertivas

Para realizar a depuração de uma classe ou trecho de código, é útil declarar as condições verdadeiras em um certo ponto do código. A essas condições dá-se o nome de Declarações ou Assertivas (Assertions). Elas ajudam a assegurar a validade do programa identificando possíveis erros de lógica e bugs.

[Java] Criar e usar tipos enumerados


Uma enumeração é um tipo especial de classe que é introduzida pela palavra-chave enum e um nome de tipo. Assim como todas as classes as chaves { e } delimitam o corpo da declaração enum. Entre as chaves contém uma lista de constantes de enumeração separadas por vírgulas. Cada identificador em uma enum devem ser únicos.

Como todas as classes, os tipos enum são tipos por referência. Uma declaração do tipo enum pode opcionalmente incluir construtores, campos e métodos.Características da classe enum:
  1. Tipos enum são implicidamente final.
  2. Constantes enum são implicidamente static.
  3. Se tentar criar um objeto de um tipo enum irá resultar em erro de compilação.

Usar tipos enumerados

Segue abaixo exemplo de declaração e utilização de classe enum. Verifique que no exemplo a classe enum possui campo, construtor e método.
//Classe enum Naipe
public enum Naipe {
ESPADAS ("Espadas"),
COPAS ("Copas"),
PAUS ("Paus"),
OUROS ("Ouros");

// Campo
private final String nome;

// Construtor
private Naipe (String nome) {
this.nome = nome;
}

// Método
public String getNome() {
return nome;
}
}

// Classe Baralho
public class Baralho {
private Naipe naipe;
private int valor;

public Baralho(Naipe n, int v) {...}


public Naipe getNaipe() {...}
public int getValor() {...}


public String getNomeNaipe() {...}
}

// Classe TestaBaralho
public class TestaBaralho {
public static void main(String[] args) {

Baralho carta1 = new Baralho(Naipe.ESPADAS, 2);
System.out.println("A carta1 é um " + carta1.getValor()
+ " de " + carta1.getNaipe().getNome());

// Isto não compilará.
// Baralho carta2 = new Baralho(47, 2);
}
}


terça-feira, 20 de julho de 2010

[Java] Abstração e métodos abstratos


Normalmente quando pensamos em classes associamos à possível criação de objetos daquele tipo. Porém exitem casos em que não necessitamos de classes para a criação de objetos daquele tipo. Classes com este propósito são as chamadas classes abstratas. Classes abstratas são comumente utilizadas para servir como "ponto de encontro" entre duas ou mais classes diferentes, porém com algumas características e métodos semelhantes. Para tornar mais claro o entendimento, considere o diagrama UML abaixo:


Neste exemplo a classe abstrata Empregado serviu como ponto de encontro para as classes Assalariado, Comissionado e Horista. Foi omitido do diagrama os métodos get/set.

Uma classe abstrata é composta por PELO MENOS 1 método abstrato. Um método abstrato é aquele que não possui implementação e declarado com a palavra-chave abstract. Toda classe abstrata deve ser declarada usando a palavra-chave abstract. As subclasses de uma classe abstrata DEVEM implementar TODOS os métodos abstratos.

Veja o abaixo a implementação do diagrama UML do exemplo.
// Classe Abstrata
public abstract class Empregado {
private String nome;
private String sobrenome;
private String cpf;
public Empregado(){ }
public Empregado(String n, String s, String c){...}
public String getNome(){...}
public void setNome(String n){...}
public String getSobrenome(){...}
public void setSobrenome(String s){...}
public String getCpf(){...}
public void setCpf(String c){...}
//Método Abstrato
public abstract double salario();
}
//Classe Assalariado
public class Assalariado extends Empregado {
private double salario;

public double getSalario() {...}
public void setSalario(double s) {...}

//Implementa o método abstrato
public double salario() {
return getSalario();
}

}
//Classe Comissionado
public class Comissionado extends Empregado {

private double totalVenda;
private double taxaComissao;
public double getTotalVenda() {...}
public void setTotalVenda(double tv) {...}
public double getTaxaComissao() {...}
public void setTaxaComissao(double tc) {...}

//Implementa o método abstrato
public double salario() {
return getTotalVenda() * getTaxaComissao();
}
}
//Classe Horista
public class Horista extends Empregado {
private double precoHora;
private double horasTrabalhadas;
public double getPrecoHora() {...}
public void setPrecoHora(double ph) {...}
public double getHorasTrabalhadas() {...}
public void setHorasTrabalhadas(double ht) {...}

//Implementa o método abstrato
public double salario() {
return getPrecoHora() * getHorasTrabalhadas();
}
}

Apesar das classes abstratas não puderem ser instanciadas é possível declarar variáveis da classe abstrata para armazenar referências de qualquer classe concreta (contanto que seja uma subclasse dela). E só! :)

[Java] Descrever a operação completa de construção e de inicialização de objeto


A operação de construção e inicialização de objeto já foi tratado neste post.

[Java] Descrever os conceitos de sobrecarga de construtores e método


Este assunto já foi tratado anteriormente por este post.

[Java] Usar os modificadores de acesso protegidos e padrão


Os modificadores de acesso protegido e padrão (protected e default) já foram tratados anteriormente neste post.