quarta-feira, maio 23, 2007

Modificador Static

Você sabe o que significa a bendita palavra static no Java?
Vejo muita gente fazendo confusão sobre esse assunto, sem entender o que é ou quando usar etc...
Bem, como de costume, lá vem um exemplinho básico do emprego de variáveis estáticas.

Imagine que nós estamos aqui, sem nada para fazer, e vamos representar dois objetos do mundo real em condições de uso típicas do mundo real (é, nada daqueles exemplos esdrúxulos como classe xyz variáveis foo, bar... :P): duas bicicletas.

Uma delas é uma montainbike, e o camarada está se desprendendo do topo de uma montanha qualquer no melhor estilo suicida, o outro cara está em uma bicicleta do tipo de corrida de velocidade, subindo uma ladeira.

Bom vamos ver o que as nossas classes precisam ter para que se represente os objetos reais:

- Tipo;
- Modelo;
- Número de marchas;
- Aro
- Marcha atual;
- Velocidade.

Bem, vamos então a nossa classe Bibicleta:

public class Bicicleta {

    private String tipo;
    private String modelo;
    private int marchas;
    private int aro;
    private int marchaCorrente;
    private static double velocidade;

    public String getTipo() {
        return tipo;
    }

    public void setTipo(String tipo) {
        this.tipo = tipo;
    }

    public int getAro() {
        return aro;
    }

    public void setAro(int aro) {
        this.aro = aro;
    }

    public int getMarchas() {
        return marchas;
    }

    public void setMarchas(int marchas) {
        this.marchas = marchas;
    }

    public String getModelo() {
        return modelo;
    }

    public void setModelo(String modelo) {
        this.modelo = modelo;
    }

    public void setMarchaCorrente(int marchaCorrente) {
        this.marchaCorrente = marchaCorrente;
    }

    public int getMarchaCorrente() {
        return this.marchaCorrente;
    }

    public static void frear() {
        Bicicleta.velocidade--;
    }

    public static void acelerar(int velocidade) {
        Bicicleta.velocidade += velocidade;
    }

    public static double getVelocidade() {
        return Bicicleta.velocidade;
    }

    public Bicicleta() {
    }

    public String toString() {
        String texto = "Tipo: " + this.getTipo() +
                       " Madelo: " + this.getModelo() +
                       " Marchas: " + this.getMarchas() +
                       " Aro: " + this.getAro();

        return texto;
    }

    public Bicicleta(String tipo, String modelo, int marchas, int aro) {
        this.tipo = tipo;
        this.modelo = modelo;
        this.marchas = marchas;
        this.aro = aro;
    }
}

Notem o seguinte, nossa classe tem um campo definido como estático (static), o campo velocidade. Estático na sua definição quer dizer: adj. relativo ao equilíbrio das forças, paralisado, imóvel, firme, em repouso. Paralisado é o mais importante para nós.

Imagine que um campo estático é um cara que uma vez que se cria o objeto e se atribui um valor a ele todas as demais estâncias da nossa classe passam a assumir este valor.

Ou seja criamos uma bicicleta com a nossa classe assim:

Bicicleta b0 = new Bicicleta("Montainbike", "Caloi Aluminum", 21, 26);

Agora vamos configurar alguns estados a ela:

b0.setMarchaCorrente(21);
b0.acelerar(45);

Beleza, o que quer dizer que o cara está na marcha 21 a 45km/h, porém vamos ver o que acontece ao criarmos mais uma bicicleta:

Bicicleta b1 = new Bicicleta("Speed", "Caloi Estrada", 10, 28);
b1.setMarchaCorrente(1);
b1.acelerar(9);

Bom, vejamos o que o método acelerar faz: Bicicleta.velocidade += velocidade; Bicicleta já indica que a coisa não é específica para o objeto que chamou o método (this. indicaria isso). Logo se tínhamos 45km/h atribuído ao primeiro objeto, agora adicionamos 9km/h e compartilhamos para ambos 54kh/h como valor para o campo , e pior os dois objetos estão errados agora. Cheque com o método getVelocidade assim: bo.getVelocidade() e b1.getVelocidade(). O resultado é 54!

Entendeu como os campos estáticos se comportam? Em um programa enquanto eu estiver estanciando Bicicleta todas elas estarão com o campo velocidade apontando para o mesmo valor em memória e sempre que alguma das estâncias modificar este valor todas as demais vão ter este campo alterado.

Simples! Agora adicione o método main abaixo listado na sua classe e execute-o para ver a saídas.

    public static void main(String[] args) {
        //Criando duas bikes de modelos e características diferentes
        Bicicleta b0 = new Bicicleta("Montainbike", "Caloi Aluminum", 21, 26);
        Bicicleta b1 = new Bicicleta("Speed", "Caloi Estrada", 10, 28);

        //Checando as duas após a criação
        System.out.println(b0.toString());
        System.out.println(b1.toString());

        //Configurando a primeira
        b0.setMarchaCorrente(21);
        b0.acelerar(45);

        System.out.println("b0 está a 45km/h"); //Até aqui ok

        //Configurando a segunda
        b1.setMarchaCorrente(1);
        b1.acelerar(9); //Será?

        System.out.println("b1 está a 9km/h"); //Errado! Está a 54!

        b0.frear(); //Errado novamente, ambas as bikes estão freando!

        /*
         * Constatamos que a velocidade dela esteve errada desde o momento da
         * criação da segunda bike, pois ao setarmos a velocidade da segunda
         * somamos a velocidade pretendida para a segunda bike com a que já
         * estava atribuída a primeira! Agora decrementando em 1km/h temos o
         * valor errôneo de 53km/h ao invés dos 44km/h pretendidos com a ação.
         */
        System.out.println("b0 está agora freando, velocida está em " +
                           b0.getVelocidade() + "km/h");

        System.out.println("Bicicleta b0 está na marcha " +
                           b0.getMarchaCorrente() + " a " + b0.velocidade +
                           " km/h");

        System.out.println("Bicicleta b1 está na marcha " +
                           b1.getMarchaCorrente() + " a " + b1.velocidade +
                           " km/h");
    }

Lembrando que métodos podem ser estáticos também. Onde normalmente se tem estância.método para poder invocar um método, métodos estáticos não precisam disto, podem (e devem) ser invocados sem a referência ao objeto invocador. Exemplo disso é em nossa própria classe Bicicleta, em que o método frear e acelerar como manipulam uma variável estática são declarados como estáticos, e estamos fazendo invocações a eles usando b0.acelelar() e b0.frear(). O correto deveria ser direto frear() e acelerar() já que afetará todas os objetos criados. Fica de tema de casa mudar as chamadas :P. Invocando só frear(), por exemplo, sem referência ao objeto fica até mais fácil de se “ver” que afetará todos os objetos.

T+ pessoal, gostou, não gostou, críticas, elogios, erros... estamos sempre aí, só mandar seu comentário (se possível deixa um e-mail para que eu possa lhes responder).


Aqui tem o post em pdf, para facilitar as coisas :P


http://geocities.yahoo.com.br/sadbuttruebr/blog/
posts_pdf/estaticos.pdf

domingo, maio 20, 2007

Vídeo da SUN






sexta-feira, maio 18, 2007

Expressões Regulares - O início

Diretamente das definições da Sun :P :

Expressões regulares são uma maneira de qualificar um conjunto de strings baseado em características comuns compartilhadas por cada string no conjunto. Elas podem serem usadas para procurar, editar ou manipular texto e dados.

:(

Bem vou tentar desmistificar esse assunto fazendo, claro, um exemplo usando a API java.util.regex do Java.

Expressões regulares variam de complexabilidade mas uma vez que você aprender os conceitos básicos do assunto será capaz de lê-las e escrevê-las sem dificuldades.

Vamos primeiro ver 3 classes chaves para o uso de expressões regulares em Java: Pattern, Matcher e PatternSyntaxExeption.

a) Pattern: É a representação compilada da expressão regular. Não há um construtor público na classe. Para criar um pattern você precisa primeiro invocar um dos métodos compiladores públicos e estáticos da classe que retornarão um objeto Pattern. Estes métodos aceitam como argumento uma expressão regular.

b) Matcher: É o mecanismo de interpretação que interpretará o pattern e confrontará-o contra a string passada para ele. Assim como a classe Pattern, Matcher não define um construtor público. Você obtem um objeto do tipo Matcher invocando o método matcher do objeto Pattern.

c) PatternSyntaxException: Esta é facinha né! :) Nada mais é do que uma exceção que ocorre quando se tem um erro na sintaxe do pattern.

Vamos ao primeiro exemplo: uma classe que procure por ocorrências de um conjunto de caracteres (uma string) em uma sentença qualquer.

ExemploExpressoesRegulares.java

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ExemploExpressoesRegulares {
public static void main(String[] args) {
        System.out.println("--- Teste Com Expressões Regulares ---");

        String sentenca = "Post sobre Expressões Regulares (java.util.regex API).";

        String expressao = "Post";

        Pattern regra = Pattern.compile(expressao);

        Matcher confrontador = regra.matcher(sentenca);

        while(confrontador.find()) {
            System.out.printf("Encontrado \"%s\" de %d a %d.%n",
                                           confrontador.group(),
                                           confrontador.start(),
                                            confrontador.end());
        }

        System.out.println("--------------------------------------");
    }
}

Saída:

--- Teste Com Expressões Regulares ---
Encontrado "Post" de 0 a 4.
--------------------------------------

Vamos ver o que fizemos em detalhes... ou em partes, como diria Jack, o estripador :D.
    1)Importamos os dois objetos que precisamos: Pattern e Matcher;
    2)Criamos duas strings, uma com uma sentença qualquer e uma com a nossa expressão a ser pesquisada;
    3)Depois criamos um Pattern com a expressão e um Matcher à partir do Patter passando como parâmetro a nossa sentença;
    4)Em um laço (enquanto forem encontradas ocorrências da nossa regra) imprimimos onde encontramos na sentença a nossa expressão (os índices). Notem que por convenção o índice das ocorrências sempre englobam mais uma posição (coisas da Sun). Faça o teste com a seguinte sentença postpostpost e na expressão use post:

    012345678901 índices
    postpostpost sentença

    Saída:

    --- Teste Com Expressões Regulares ---
    Encontrado "post" de 0 a 4. ??? Aaaaaaaaaaaaaah!
    Encontrado "post" de 4 a 8. ??? Aaaaaaaaaaaaaah!
    Encontrado "post" de 8 a 12. ??? Aaaaaaaaaaaaaah!
    --------------------------------------

Note que o índice de início da ocorrência seguinte é sempre o índice final da ocorrência anterior.

A API também da suporte uma série de caracteres especiais que alteram a forma como são coincididas as sentenças com a expressão.
Vamos testar isso usando agora a sentença: Eu tenho dois carros que trato com carinho e na expressão: carro. Resultado:

--- Teste Com Expressões Regulares ---
Encontrado "carro" de 14 a 19.
--------------------------------------

Agora usaremos de um dos n caracteres especiais suportados, o ponto final (.) em nossa expressão: car. (com ponto final). Resultado:

--- Teste Com Expressões Regulares ---
Encontrado "car." de 14 a 18.
Encontrado "car." de 35 a 39.
--------------------------------------

Note a diferença no resultado. O resultado é referente a carr e cari e não a car apenas (se fosse os índices seriam de 14 a 18 e de 35 a 38!). Para confirmar isso vamos mudar nosso programa. Onde usamos o comando printf vamos colocar ao invés de expressao o comando confrontador.group():

System.out.printf("Encontrado \"%s\" de %d a %d.%n",
                               confrontador.group(),
                               confrontador.start(),
                                confrontador.end());

Agora rodemos novamente o programa e a saída será:

--- Teste Com Expressões Regulares ---
Encontrado "carr" de 14 a 18.
Encontrado "cari" de 35 a 39.
--------------------------------------

Esses caracteres especiais como o ponto final (.) são chamados de meta caracteres – são caracteres com um significado especial para o interpretador.
Eis todos suportados pela API: ([{\^-$|]})?*+..
Alguns desses não podem ser usados sozinhos, pois devem formar uma parte da expressão (visto mais além). Também notem que !, @ e # nunca são meta caracteres.

Meta caracteres podem ser usados para formar-se conjuntos ao qual a sentença deva atender como regra geral.
Por exemplo, poderíamos ver se a sentença contem qualquer palavra com o prefixo pedr:
Expressão: pedr.*
Sentença: pedreiro Ok
Sentença: pedra Ok
Sentença: pedreira Ok
Sentença: pedal Nok

Agora você pergunta, ta mas eu tenho que criar minha regra sempre em maiúsculo e depois em minúsculo?
Claro que não, modificaremos nossa classe novamente:

Pattern regra = Pattern.compile(expressao, Pattern.CASE_INSENSITIVE);

Pronto, se agora passarmos: Pedra, PEDRA, PeDreiRa, etc... irá funcionar!

Com os meta caracteres você pode criar regras mais complexas, unir certas condições, especificas faixas de valor/ocorrências, etc... vejamos:

[a-c] Caracteres entre a e c (inclusive) ou [a-cA-C].
[a-c[e-z]] Qualquer caractere que não seja d.
[a-f&&[cd]] Somente c e d.
[^a-c] Qualquer caracteres que não esteja entre a e c.
[a-f&&[^cd]] Qualquer caracter entre a e f menos c e d.

Assim por diante...

Ainda há com verificar se há dígitos (\\d), caracteres que não sejam dígitos (\\D – o mesmo que [^0-9]) , etc... veja a lista completa na documentação da API.

Agora, na finaleira vamos ver se uma sentença tem apenas números. Para isso mudaremos nossa classe novamente. Onde tem o while vai ter o seguinte if:

if(confrontador.matches()) {
    System.out.printf("Entrada \"%s\" está conforme o padrão %s.%n",
                                                           sentenca,
                                                         expressao);
}
else {
    System.out.printf("Entrada \"%s\" não está conforme o padrão %s.%n",
                                                               sentenca,
                                                             expressao);
}

Agora a nossa expressão fica: \\d* e a nossa sentença: 01234 . Rode o exemplo, depois mude a sentença e assim por diante.

Bom o assunto é muito mais extenso que esse meu post, espero ter aguçado a curiosidade de vocês e que procurem na documentação da API mais informações assim como no Java Tutorial, etc...

Até a próxima pessoal.

Gostou? Não gostou? Achou algum erro? Comenta aí, não leva nem um minuto e me ajudará muito! :D

Aqui tem o post em pdf, para facilitar as coisas :P


http://geocities.yahoo.com.br/sadbuttruebr/blog/
posts_pdf/expressoes_regulares.pdf

terça-feira, maio 15, 2007

Trabalhando com arquivos .properties

Esses dias tive que manipular um arquivo .properties e não tinha muita noção de como o fazer, então fui dando uma fuçada aqui e ali e achei na API tudo que eu precisava e fiz o que eu queria.

Bom para efeitos didáticos e de salvamento, se alguém tiver no sufoco e tiver que fazer isso também, ta aí a classezinha que quebra o galho (na verdade não é a versão final do que eu fiz, mas daqui eu parti para o que eu precisava).

Primriro criei um arquivo de propriedades para testes. Arquivos de propriedades são aquivos contendo texto em que a cada linha se tem um par de chave e valor.

configuracoes.properties:

sistema=xyz
versao=0.0.1
plataforma=MS Windows
sgbd=MySQL
autor=Jean Jorge Michel

Agora eu queria algumas funcionalidades na minha classe (já que eu ia fazer um cara que pelo menos lesse o arquivo, eu já faria alterar e salvar também):

- public java.util.Properties carregarPropriedades(java.lang.String origem);
- public void imprimir(java.util.Map propriedades);
- public java.lang.String getPropriedade(java.util.Properties propriedades, java.lang.String propriedade);
- public java.util.Properties incluirPropriedade(java.lang.String chave, java.lang.String valor, java.util.Properties propriedades);
- public java.util.Properties removerPropriedade(java.lang.String chave, java.util.Properties propriedades);
- public void salvar(java.util.Map propriedades, java.lang.String destino).

Esses são os métodos que eu tenho na minha classe. Agora lá vem ela:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
* @author Jean Jorge Michel
* @version 1.0
*/
public class ManipuladorProperties {

    /**
     * Método que retorna um objeto Properties com as informações do sistema.
     * @param arquivo O Caminho físico do arquivo e seu nome.
     * @return Um objeto Properties.
     */
    public Properties carregarPropriedades(String origem) {
        FileInputStream arquivoConfig = null;

        Properties configSistema = new Properties();

        try {
            arquivoConfig = new FileInputStream(origem);

            configSistema.load(arquivoConfig);
        }
        catch(FileNotFoundException e) {
            e.printStackTrace();
        }
        catch(IOException e) {
            e.printStackTrace();
        }
        finally {
            try {
                arquivoConfig.close();
            }
            catch(IOException e) {
                e.printStackTrace();
            }
        }

        return configSistema;
    }

    /**
     * Método que imprime no console todas as propriedades e seus respectivos
     * valores encontradas no arquivo de propriedades.
     * @param propriedades Um objeto do tipo Properties.
     */
    public void imprimir(Map propriedades) {
        Set<String> valores = propriedades.keySet();

        for(String valor: valores) {
            System.out.println(valor + "=" + propriedades.get(valor));
        }
    }

    /**
     * Método que retorna o valor de uma propriedade de acordo com o seu nome.
     * @param propriedades Um objeto do tipo Properties.
     * @param propriedade Nome da propriedade.
     * @return O valor da propriedade.
     */
    public String getPropriedade(Properties propriedades, String propriedade) {
        return propriedades.getProperty(propriedade);
    }

    /**
     * Método que adiciona ao objeto Properties mais uma propriedade.
     * @param chave O nome da nova propriedade a incluir.
     * @param valor O valor da nova propriedade
     * @param propriedades O objeto Properties a ser modificado.
     * @return Retorna o objeto Properties modificado.
     */
    public Properties incluirPropriedade(String chave,
                                         String valor,
                                         Properties propriedades) {
        propriedades.put(chave, valor);

        return propriedades;
    }

    /**
     * Método que remove do objeto Properties uma propriedade.
     * @param chave A propriedade a ser removida
     * @param propriedades O objeto Properties a ser modificado.
     * @return Retorna o objeto Properties modificado.
     */
    public Properties removerPropriedade(String chave, Properties propriedades) {
        propriedades.remove(chave);

        return propriedades;
    }

    /**
     * Método que persiste no disco o arquivo properties.
     * @param propriedades O objeto Properties a ser gravado.
     * @param destino O caminho físico e o nome do arquivo a ser criado.
     */
    public void salvar(Map propriedades, String destino) {
        FileWriter fw = null;
        
        try {
            fw = new FileWriter(destino);

            Set<String> valores = propriedades.keySet();

            for(String valor: valores) {
                fw.write(valor + "=" + propriedades.get(valor) + "\r\n");
            }
        }
        catch(FileNotFoundException e) {
            e.printStackTrace();
        }
        catch(IOException e) {
            e.printStackTrace();
        }
        finally {
            try {
                if (fw != null) {
                    fw.close();
                }
            }
            catch(IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Para testar:

String caminho = "C://temp//";
String arquivo = "configuracoes.properties";

ManipuladorProperties mp = new ManipuladorProperties();
Properties configSistema = mp.carregarPropriedades(caminho + arquivo);

//Lista as propriedades
mp.imprimir(configSistema);

//Recupera uma propriedade específica
System.out.println(mp.getPropriedade(configSistema, "autor"));

//Inclui uma propriedade nova
mp.incluirPropriedade("data", new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new Date()), configSistema);

//Grava o arquivo, neste caso com outro nome
mp.salvar(configSistema, caminho + "novas_propriedades.properties");

É isso aí, esta feito quem quiser usar pode usar, sem nenhuma garantia claro. :)

Gostou, quer criticar, sugerir algo... comente aí o post!

sexta-feira, maio 11, 2007

Annotations - Primeiro contato

Dae, tudo tranquilo?
Bom esses dias (depois de ter dado uma estudada em threads) andei dando uma aprofundada em Annotations.

Pó que saco, tudo que era lugar que eu lia sobre dizia a mesma coisa: anotações são meta-dados que blablabla... E uns exemplos muito complexos pra quem tava querendo entender para que um dia EU usaria essa funcionalidade do Java.v

Bem, então... hã... hun... pensei, pra mim ver para que serve tenho que fazer um exemplo, seja ele bizarro ou real eu preciso fazer. Então defini o seguinte:

Um POJO chamado Cliente (que original!);
Uma annotation chamada Validar;
Uma classe que interaja com meu POJO chamada CadastroCliente;
Uma classe que use dos campos anotados do meu POJO fazendo alguma coisa, neste caso validando-o.

Então o seguinte, annotations nada mais são do que meta-dados que estão nas classes e não servem pra pombas nenhuma, a não ser que alguém saiba o que fazer com eles. Exemplos clássicos são o modificador transient, que é uma anotação que informa ao mecanismo de serialização que o campo não deve ser serializado, a tag @deprecated do Java Doc, que indica que um método ira ser descontinuado em versões futuras da classe, e por aí vai. A vantagem que agora o desenvolvedor pode criar as suas anotações.

Bem o que meu exemplo faz é o seguinte, todo campo no meu POJO que tiver marcado com a anotação @Validar vai ser validado por um mecanismo através de reflection (papo para ouuuuutro post :P ).

Então criei a anotação, que nada mais é do que uma “interface” com @ antes da palavra reservada interface e que eu posso definir um nível de atuação para ela, no meu casso campos (poderia ser método, classe, etc... veja na API java.lang.annotation.ElementType os tipos permitidos) e que será usada em tempo de execução (também há uma lista de valor fixos na API java.lang.annotation.RetentionPolicy):

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Validar {
}

Depois disso criei meu POJO, e disse quais os campos dele serão validados:

public class Cliente {

    @Validar
    private String nomeCompleto;

    @Validar
    private int idade;
    
    private String email;

    public String getNomeCompleto() {
        return nomeCompleto;
    }

    public void setNomeCompleto(String nomeCompleto) {
        this.nomeCompleto = nomeCompleto;
    }

    public int getIdade() {
        return idade;
    }

    public void setIdade(int idade) {
        this.idade = idade;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Cliente() {
    }

    public Cliente(String nome, int idade) {
        this.nomeCompleto = nome;
        this.idade = idade;
    }

    public Cliente(String nome, int idade, String email){
        this.nomeCompleto = nome;
        this.idade = idade;
        this.email = email;
    }
}

Note que o campo que armazenará o e-mail do cliente não será validado, poderá ser nulo ou qualquer texto inválido para endereço eletrônico.

Agora sim, meu validador que vai pegar o objeto ver seus campos, ver os que estão “anotados” e fazer algumas validações:

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class ValidadorCadastro {
    public static String nvl(String entrada) {
        String saida = "";

        if(entrada == null) {
            saida = "";
        }
        else {
            saida = entrada;
        }

        return saida;
    }

    public List<String> validarCadastro(Cliente c) throws IllegalAccessError, Exception {

        Field[] fields = c.getClass().getDeclaredFields();

        String nomeCliente = null;

        Integer idade = null;

        List<String> erros = new ArrayList<String>();

        for (Field field : fields) {
            if (field.isAnnotationPresent(Validar.class)) {

                field.setAccessible(true);

                if(field.getName().equals
("nomeCompleto")) {

                    nomeCliente = (String)field.get(c);
                    if(nvl(nomeCliente).length() < 4) {
                        erros.add("O nome do cliente deve ter mais " +
                                  "de 4 caracteres.");
                    }
                }

                if(field.getName().equals("idade")) {
                    idade = (Integer)field.get(c);
                    if(idade < 18) {
                        erros.add("O cliente deve ser maior de idade.");
                    }
                }

                if (field.get(c) == null) {
                    erros.add("Campo [" + field.getName() + "] não " +
                              "preenchido.");
                }
            }
        }

        return erros;
    }
}

E uma classe simples que interaja com o POJO e o validador:

import java.util.List;

public class CadastroCliente {

    public static void main(String[] args) {
        Cliente c0 = new Cliente("Jean Jorge Michel", 25);

        List<String> errosCadastro = null;

        ValidadorCadastro vc = new ValidadorCadastro();

        try {
            errosCadastro = vc.validarCadastro(c0);

            if(! errosCadastro.isEmpty()) {
                for(String erroOcorrido : errosCadastro) {
                    System.out.println(erroOcorrido);
                }
            }
            else {
                System.out.println("Cadastro concluído com sucesso!");
            }
        }
        catch(IllegalAccessError e) {
            e.printStackTrace();
        }
        catch(Exception e) {
            e.printStackTrace();
        }
    }
}

Rodando a classe assim como está não há problemas, vai passar na validação... agora troque o nome, diminua a idade, não informe o nome... e a lista de problemas encontrados será exibida.

Bom, é uma aplicação para as anotações mas claro que há outras, como configuração de frameworks por exemplo. Veja o Hibernate annotation :).

Era isso, de tema para casa fica validar o campo e-mail também :D.

Gostou, não gostou, achou um erro, quer me xingar: comente o post!

terça-feira, maio 08, 2007

Introdução a Threads - Programação paralela

Você sabe o que é uma Thread? Tem uma vaga idéia pelo menos (como eu tinha até alguns dias atrás)? Bom vou escrever aqui sobre esse bichinho místico que apavora todo mundo que pensa na prova de certificação Java :P .

Bom thread referisse ao processamento paralelo em Java... bá que grande ajuda a minha para você não é? Ta bom, vamos ver então mais didaticamente, diretamente do Java tutorial a Sun que diz mais ou menos isso:

Usuários de computadores têm a certeza de que seus sistemas podem fazer mais de uma coisa ao mesmo tempo. Eles assumem que eles podem continuar trabalhando em um editor de textos, enquanto outras aplicações descarregam arquivos, gerenciam a pilha de impressões, e reproduzem áudio. Desde uma simples aplicação é esperado que ela faça mais de uma coisa ao mesmo tempo. Por exemplo, uma aplicação que reproduz áudio deve simultaneamente ler o arquivo digital da rede, descompactá-lo, gerenciar a lista de músicas, e atualizar o visor. Até um editor de texto deve sempre ler e responder aos eventos de teclado e mouse, não importando o quanto ocupado ele já esteja reformatando textos ou atualizando o monitor. Um programa que pode fazer isso é conhecido como uma aplicação concorrente.

Sacou? Dae as THREADS meu filho! :)

Bueno, se tu for lá no Java Tutorial vai ver que eles falam em processos e threads... eu não pretendo escrever aqui, ou traduzir, sobre o que é isso - essa diferença - meu intuito é apenas mostrar como usar threads e algumas das opções que temos quando trabalhamos com elas (como sleep, join, etc...).

Bom entenda que você pode implementar uma thread de duas maneiras:

- Implementando a interface Runnable que declara o método run que contém o código da thread. Este objeto Runnable é passado por parâmetro para o contrutor do objeto Thread, como no exemplo abaixo:

public class ObjetoRunnable implements Runnable {

public void run() {
String passos[]=
new String[]{"Lendo arquivo properties...",
"Recuperando URL do SGBD...", "Recuperando usuário
e senha de acesso a base...", "Abrindo uma conexão...",
"Salvando dados...",};

for(int i = 0; i <>
System.out.println(passos[i]);
}
}

public static void main(String[] args) {
Thread t = new Thread(new ObjetoRunnable());
t.start();

System.out.println("... fazendo qualquer outra coisa...");
}
}

A saída impressa no console é:

... fazendo qualquer outra coisa...
Lendo arquivo properties...
Recuperando URL do SGBD...
Recuperando usuário e senha de acesso a base...
Abrindo uma conexão...
Salvando dados...

- Estendendo a classe Thread. A própria classe Thread implementa Runnable, Embora seu método run não faça nada. Uma aplicação pode estender Thread, provendo sua própria implementação de run, como no exemplo abaixo:

public class ObjetoThread extends Thread{
public void run() {
String passos[]=
new String[]{"Lendo arquivo properties...",
"Recuperando URL do SGBD...", "Recuperando usuário
e senha de acesso a base...", "Abrindo uma conexão...",
"Salvando dados...",};

for(int i = 0; i <>
System.out.println(passos[i]);
}
}

public static void main(String[] args) {
ObjetoThread objT = new ObjetoThread();
objT.start();

System.out.println("... fazendo qualquer outra coisa...");
}
}

A saída é a mesma que a do outro exemplo. Note que invocamos o método start() e deixamos ele rodando enquanto seguimos em frente. Prova "viva" do paralelismo do nosso programa :).

Bem é mais provável que você veja e use a primeira abordagem, pois ela é mais flexível que a segunda por não lhe forçar a estender uma classe, o que poderia lhe limitar em algum momento.

Bom nossos exemplos não são de grande serventia, mas pense em um programa que você precise desviar o fluxo dividindo uma atividade. Aqui nos exemplo as threads estão funcionando de forma assíncrona uma vez que a thread principal (main), que todo programa Java tem, não espera pelo resultado da outra thread mas você poderia delegar a uma thread uma tarefa que não está no escopo do seu programa, como preparar alguma coisa no sistema ou fazer uma validação qualquer, e aguardar o seu término para seguir em frente.

Bom, foi apenas um overview, quem quiser saber mais sobre o assunto deve ler o Java Tutorial e pesquisar mais a fundo sobre o assunto em livros e sites mas eu prometo que uma hora dessas eu posto um exemplo de thread síncrona :P.