Mostrando postagens com marcador java. Mostrar todas as postagens
Mostrando postagens com marcador java. Mostrar todas as postagens

quarta-feira, outubro 23, 2013

Não deixe o básico da orientação a objetos de lado, nunca!

Quando olho para trás lembro-me de quando eu era um humilde padawan que queria ser um monge Jedi em Java, e lembro claramente dos conselheiros Jedi do RSJUG falando "vá pelo caminho da orientação a objetos". Se passaram alguns muitos anos e eu ainda lembro e sou fiel a esse princípio, e quando vejo por aí classes ou entidades de banco de dados, que eu irei ter que transformar em classes¹, contendo 181 campos (não é piada!) minha gastrite quase me mata!

Eu não sei por que as pessoas teimam em ter campos como CPF, CNPJ, data de inicio e de fim, etc em certas classes. A quem vai ficar destinada a tarefa de validar um CNPJ/CPF? Ou se a data de início não é maior do que a de fim? Não tenha receio de criar classes que não serão persistidas. As pessoas tem a imagem de que classes de domínio/modelo só devem existir se forem ser persistidas, o resto é classe útil, DAO, service, etc. e não é bem por aí.

É do domínio da minha aplicação um CNPJ/CPF! E eu tenho que ter um objeto para isso, com a responsabilidade de validar se ele mesmo é válido. Não vou jogar essa responsabilidade para uma classe megazord no pacote útil responsável por validar isso e, talvez, mais coisas em um único lugar (olha o acoplamento aíííííííí gente).

Bem, para exemplificar isso, vou mostrar um código/abordagem que gosto muito, onde eu separo o campo nome da classe usuário em um objeto a parte.

Se você parar para pensar, o nome deve conter sempre 3 campos: primeiro nome, inicial do meio e último(s) nome(s). Mas e o usuário SISTEMA? Ele não tem sobrenome. E o John Doe que não tem nome do meio?

Então eu tenho a classe PersonName:

using System;
using System.Text;

namespace com.blogspot.jeanjmichel.model
{
    public class PersonName
    {
        private String firstName;
        private String middleInitial;
        private String lastName;
        
        public String FirstName
        {
            set { this.firstName = value; }
            get { return this.firstName; }
        }
        
        public String MiddleInitial
        {
            set { this.middleInitial = value; }
            get { return this.middleInitial; }
        }
        
        public String LastName
        {
            set { this.lastName = value; }
            get { return this.lastName; }
        }
        
        public PersonName()
        {
        }
        
        public PersonName(String firstName)
        {
            this.FirstName = firstName;
        }
        
        public PersonName(String firstName, String middleInitial,
                          String lastName)
        {
            this.FirstName = firstName;
            this.MiddleInitial = middleInitial;
            this.LastName = lastName;
        }
        
        public override String ToString()
        {
            StringBuilder sb = new StringBuilder();
            
            sb.Append(this.LastName);
            sb.Append(", ");
            sb.Append(this.FirstName);
            sb.Append(" ");
            sb.Append(this.MiddleInitial);
            
            return sb.ToString();
        }
    }
}

E agora a classe User:

using System;
using System.Text;

namespace com.blogspot.jeanjmichel.model
{
    public class User
    {
        #region attributes
        
        Int64 id;
        String username;
        PersonName personName;
        char gender;
        String password;
        char active;
        
        #endregion
        
        #region properties
        
        public Int64 Id
        {
            set { this.id = value; }
            get { return this.id; }
        }
        
        public String Username
        {
            set { this.username = value; }
            get { return this.username; }
        }
        
        public PersonName PersonName
        {
            set { this.personName = value; }
            get { return this.personName; }
        }
        
        public char Gender
        {
            set { this.gender = value; }
            get { return this.gender; }
        }
        
        public String Password
        {
            set { this.password = value; }
            get { return this.password; }
        }
        
        public char Active
        {
            set { this.active = value; }
            get { return this.active; }
        }
        
        #endregion
        
        /// <summary>
        /// Returns a string with this instance's data
        /// The format of the string is:
        /// namespace + class name + [ + the fields most representative
        /// of the class + ].
        /// </summary>
        /// <returns>Returns a string with this instance's data</returns>
        public override String ToString()
        {
            StringBuilder sb = new StringBuilder();
            
            sb.Append("com.blogspot.jeanjmichel.model.User [");
            sb.Append(this.PersonName);
            sb.Append(" as '");
            sb.Append(this.Username);
            sb.Append("'");
            sb.Append(" Active: ");
            sb.Append(this.Active);
            sb.Append("]");
            
            return sb.ToString();
        }
        
        public User()
        {
        }
        
        public User(String username, PersonName personName, String password,
                    char active)
        {
            this.Username = username;
            this.PersonName = personName;
            this.Password = password;
            this.Active = active;
        }
        
        public User(Int64 id, String username, PersonName personName,
                    char gender, String password, char active)
        {
            this.Id = id;
            this.Username = username;
            this.PersonName = personName;
            this.Gender = gender;
            this.Password = password;
            this.Active = active;
        }
    }
}

Agora criando um usuário:

using System;
using com.blogspot.jeanjmichel.model;

namespace com.blogspot.jeanjmichel
{
    class Program
    {
        static void Main(string[] args)
        {
            PersonName pn = new PersonName("Jean", "J", "Michel");
            User u = new User("jmichel", pn, "Senha", 'Y');
            
            Console.WriteLine(u);
            Console.ReadKey();
        }
    }
}

A saída é: com.blogspot.jeanjmichel.model.User [Michel, Jean J as 'jmichel' Active: Y].

Quase tudo funcionou.
Mas no teste unitário quando eu digo que criando o usuário System assim:

using System;
using com.blogspot.jeanjmichel.model;

namespace com.blogspot.jeanjmichel
{
    class Program
    {
        static void Main(string[] args)
        {
            PersonName pn = new PersonName("System");
            User u = new User("sysadmin", pn, "Senha", 'Y');
            
            Console.WriteLine(u);
            Console.ReadKey();
        }
    }
}

Eu espero o resultado: com.blogspot.jeanjmichel.model.User [System as 'sysadmin' Active: Y] o que acontece?

Failed TestUserToStringMethod TestProject Assert.AreEqual failed.
Expected:<com.blogspot.jeanjmichel.model.User [System as 'sysadmin' Active: Y]>.
Actual..:<com.blogspot.jeanjmichel.model.User [, System as 'sysadmin' Active: Y]>.


Holly crap! Então, a resposabilidade da minha classe PersonName é validar esse tipo de coisa. Refatorando-a teremos:

using System;
using System.Text;

namespace com.blogspot.jeanjmichel.model
{
    public class PersonName
    {
        private String firstName;
        private String middleInitial;
        private String lastName;
        
        public String FirstName
        {
            set { this.firstName = value; }
            get { return this.firstName; }
        }
        
        public String MiddleInitial
        {
            set { this.middleInitial = value; }
            get { return this.middleInitial; }
        }
        
        public String LastName
        {
            set { this.lastName = value; }
            get { return this.lastName; }
        }
        
        public PersonName()
        {
        }
        
        public PersonName(String firstName)
        {
            this.FirstName = firstName;
        }
        
        public PersonName(String firstName, String middleInitial,
                         String lastName)
        {
            this.FirstName = firstName;
            this.MiddleInitial = middleInitial;
            this.LastName = lastName;
        }
        
        public override String ToString()
        {
            StringBuilder sb = new StringBuilder();
            
            if (String.IsNullOrEmpty(this.LastName))
            {
                sb.Append(this.FirstName);
            }
            else
            {
                sb.Append(this.LastName);
                sb.Append(", ");
                sb.Append(this.FirstName);
                sb.Append(String.IsNullOrEmpty(this.MiddleInitial) ? "" :
                " " + this.MiddleInitial);
            }
            
            return sb.ToString();

        }
    }
}

Eu faço o mesmo com CNPJ/CPF, datas (eu crio uma classe chamada período) e outras.

¹ Eu não criei uma classe com 181 campos, mas também não pude refatorar a classe, a tabela, etc (software de terceiros). então criei uma classe com o set mínimo de informações da tabela, que deu mais de 30 campos, e faço o enxerto do resto com os valores padrão para cada campo. Uma pena eu não poder quebrar essa maldita tabela em meia dúzia de 8 tabelas mais produtivas e reutilizáveis. Enfim, coisas da TI que o McGyver aprovaria :)

segunda-feira, setembro 27, 2010

JasperServer: Bad version number in .class file

Este blog estava a muito tempo parado, mas hoje resolvi postar aqui a solução para um problema que me tirou de combate quase três dias.
 
Estou testando e implementando o JasperServer na empresa em que trabalho como alternativa free ao Microsoft Reporting Services.
 
Tudo ocorreu bem nos testes no ambiente de desenvolvimento (leia-se localhost).
Criei um relatório que acessa uma base Oracle e um acessando uma outra base de dados SQL Server.
 
No ambiente de desenvolvimento estava usando o JasperServer 3.7.0 e para isso eu instalei o MySQL, o Tomcat 6 e rodei os arquivos Ant do JasperServer para gerar o .war que depois instalei no Tomcat. Tudo isso rodando com a versão 1.6.0_20 do JDK.
 
Para o ambiente de produção o JDK já era mais atual, o 1.6.0_21 e o JavaServer também era mais atual, a versão 3.7.1 que é uma distribuição all-in-one com o Tomcat 5.5, MySQL, etc.
Ai começaram meus problemas! :)
 
O relatório que eu desenvolvi para SQL Server não funcionava em produção acusando o seguinte erro:
 
    org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.UnsupportedClassVersionError: Bad version number in .class file
 
Bati cabeça atrás do erro fazendo várias perguntas nas listas do RIOJUG, Sou Java, RSJUG, etc e fazendo muitos despachos para Pai Google e a conclusão apontada era que a versão do JDK que foi compilado o relatório era diferente da versão do JDK em produção.
Lá fui eu atualizar o JDK no ambiente de desenvolvimento e o erro persistia em produção.
 
Até, que um camarada em uma lista de discussão deu a dica para eu checar se o Tomcat estava realmente usando o JDK que eu queria que ele usasse.
Comecei a catar o usuário e senha para acessar a área administrativa do Tomcat 5.5 que vem na distribuição do JasperServer 3.7.1 e não achei o arquivo tomcat-users.xml no diretório C:\Program Files\JasperServer-ce-3.7.1\apache-tomcat\conf, então fui ver como o bat jasperctl (C:\Program Files\JasperServer-ce-3.7.1\jasperctl.bat) inicializa o Tomcat e achei a seguinte pérola:
 
set JAVA_HOME= C:\Program Files\JasperServer-ce-3.7.1\java
set JRE_HOME= C:\Program Files\JasperServer-ce-3.7.1\java
 
Opa! O cara está apontando para um JDK e uma JRE que não é a que eu instalei no servidor, e ela está desatualizada! Beleza, foi só trocar os valores para apontar para os locais certos que o relatório passou a funcionar. ;)
 
Aqui está como ficou.
 
set JAVA_HOME=C:\Program Files\Java\JDK1.6.0_21
set JRE_HOME=C:\Program Files\Java\JRE6
 
Fica a dica.

quarta-feira, abril 28, 2010

Glassfish v3 não instala, e agora?

Glassfish v3
Mistéééééério! E agora Mr. M?

Hoje estava tentando instalar o Glassfish v3 na minha estação de trabalho, que roda Windows XP, e a instalação não concluía, logo que aparecia a apresentação do instalador o mesmo se fechava sozinho.

Google daqui, Google de lá, e nenhum despacho para pai Google me dava à resposta... próximo passo: listas de discussão (RSJUG, RIOJUG, CEJUG, SouJava e JavaSF).

Eis que veio a luz que eu precisava! O Windows estava configurado para português do Brasil e por isso não instalava, foi somente trocar para inglês dos Estados Unidos e a instalação correu normalmente.

Valeu pela dica Alexandre Tavares.

quarta-feira, setembro 05, 2007

Internacionalização em Java

Dae pessoal, não faz tanto tempo assim que postei algum “drop” de sabedoria aqui. Então vamos a mais um: internacionalização!

Diretamente das definições da Sun: “internacionalização é o processo de projetar uma aplicação, de modo que ela possa ser adaptada a varias linguagens e regiões sem mudanças de engenharia.” – leia-se mudanças no código.

Bom, você já deve ter ouvido ou lido em algum código o prefixo “i18n” ou “l10n”. i18n é a abreviação de internationalization, pois do primeiro i ao último n há 18 letras. O l10n é a abreviação de localization e segue a mesma regra do número de caracteres entre l e n.

Existem certas características em um programa internacionalizado, como:

• Dado uma localização (Locale), o mesmo binário do programa deve funcionar em qualquer lugar;
• Os dados textuais do programa (mensagens de erro, mensagens de tela, rótulos, etc...) não devem estar atribuídos de forma “hardcode” aos elementos dentro dos códigos do programa e sim externados em um arquivo apropriado;
• Suporte a outros idiomas não deve requerer nova compilação do programa;
• Dados dependentes de localização, como formatação de datas e campos monetários, devem ser apresentados de acordo com a região do usuário e seu idioma;

Bom, se você tiver sons e imagens que possam fazer sentido internacionalizar, é uma boa idéia!

Vamos cortar o nhe nhe nhe e partir para a ação.

Vamos a um simples exemplo. Uma classe que deva imprimir:

Nome: Jean Jorge Michel
Nome de usuário: jmichel
Senha: minhasenhaultrasecreta

Porém os rótulos (nome, nome de usuário e senha) devem ser impressos corretamente para cada idioma (tá, não exageremos, vamos testar com português e inglês apenas).

Então vamos começar pelos fatos primeiros (como diria o grande sábio), criando os arquivos com a tradução do nosso programa. Para isso, no pacote estudo.internacionalizacao criei dois arquivos:

• ResourceBundle_pt_BR.properties;
• ResourceBundle_en_US.properties.

E o conteúdo de cada um deles (na ordem de criação):

name=Nome
password=Senha
username=Nome de usuário

name=Name
password=Password
username=Username

Agora no mesmo pacote criei a classe Internacionalizada.java:

package estudo.internacionalizacao;

import java.util.Locale;
import java.util.ResourceBundle;

public class Internacionalizada {

    public static void main(String[] args) {

        final Locale defaultLocale = Locale.getDefault();
        final ResourceBundle rbDefault = ResourceBundle.getBundle("estudo.internacionalizacao.ResourceBundle", defaultLocale);

        System.out.println(new StringBuilder().append(rbDefault.getString("name")).append(": Jean Jorge Michel"));
        System.out.println(new StringBuilder().append(rbDefault.getString("username")).append(": jmichel"));
        System.out.println(new StringBuilder().append(rbDefault.getString("password")).append(": minhasenhaultrasecreta").append("\n\n"));

        final Locale otherLocale = new Locale("en", "GB");
        final ResourceBundle rb = ResourceBundle.getBundle("estudo.internacionalizacao.ResourceBundle", otherLocale);

        System.out.println(new StringBuilder().append(rb.getString("name")).append(": Jean Jorge Michel"));
        System.out.println(new StringBuilder().append(rb.getString("username")).append(": jmichel"));
        System.out.println(new StringBuilder().append(rb.getString("password")).append(": minhasenhaultrasecreta"));
    }
}

Agora é só rodar e ver o resultado das duas saídas que devem parecer com isso:

Nome: Jean Jorge Michel
Nome de usuário: jmichel
Senha: minhasenhaultrasecreta


Name: Jean Jorge Michel
Username: jmichel
Password: minhasenhaultrasecreta

Lembra daquela Enum do post anterior? Poderia ser internacionalizada não? :)

Até mais! Bons códigos

quinta-feira, agosto 16, 2007

Java Enum

Aeeee o blog está vivo! Eu andei sem tempo para postar aqui mas vamos lá...

A bola da vez é o tipo Enum do Java.
Uma enum (enumeração) é um conjunto de valores fixos (constantes) que podem ajudar o desenvolvedor a definir valores fixos que serão usados no sistema.

Use sempre que você quiser definir um conjunto de valores fixo como por exemplo os dias da semana, meses do ano, tipos de entidades, etc...

Vamos ao exemplo usando uma enum que armazene os dias da semana:

public enum DiasSemana {

    SEGUNDA, TERCA, QUARTA, QUINTA, SEXTA, SABADO, DOMINGO;

}

Ok, o exemplo é bem meia boca, mas vamos em frente. Por serem constantes os valores de uma enum são sempre grafados em maiúsculo.

Agora vamos fazer uma classe que utilize esses valores:

public class Agenda {
    public static void main(String[] args) {
    
        System.out.println(DiasSemana.QUINTA);
    
    }
}

A saída é: QUINTA.

Enums podem ter métodos, seus valores podem ter métodos, e toda enum “herda” métodos (nos materiais da SUN eles falam que o compilador adiciona tais métodos, não fala em herança propriamente dita e na documentação da classe o objeto Enum é filho de Object. Todas as enums que você criar serão filhas da classe java.lang.Enum e por não haver herança múltipla no Java você não pode fazer suas enums estenderem mais nada!) que facilitam a vida do desenvolvedor como o estático values() que retorna um array com os valores da enum ordenados pela declaração. Ex:

public class Agenda {
    public static void main(String[] args) {

        for(DiasSemana dia : DiasSemana.values()) {
            System.out.println(dia);
        }

    }
}

A saída é:

SEGUNDA
TERCA
QUARTA
QUINTA
SEXTA
SABADO
DOMINGO

Bem mas a nossa enum não está muito funcional, eu não exibiria em meu sistema essas entradas! ;)
Então vamos declarar métodos que formatem nossos valores para algo melhor:

public enum DiasSemana {

    SEGUNDA() {
        public String extenso() {
            return "segunda-feira";
        }
    },
    TERCA() {
        public String extenso() {
            return "terça-feira";
        }
    },
    QUARTA() {
        public String extenso() {
            return "quarta-feira";
        }
    },
    QUINTA() {
        public String extenso() {
            return "quinta-feira";
        }
    },
    SEXTA() {
        public String extenso() {
            return "sexta-feira";
        }
    },
    SABADO() {
        public String extenso() {
            return "sábado";
        }
    },
    DOMINGO() {
        public String extenso() {
            return "domingo";
        }
    };
    
    public String extenso() {
        return this.extenso();
    }
}

Vamos usar o recurso:

public class Agenda {
    public static void main(String[] args) {

        for(DiasSemana dia : DiasSemana.values()) {
            System.out.println(dia.extenso());
        }

    }
}

A saída é:

segunda-feira
terça-feira
quarta-feira
quinta-feira
sexta-feira
sábado
domingo

Beleza! Com isso foi ilustrado o fato de um tipo Enum poder ter métodos e seus atributos também.

Ainda brincando com a classe Agenda:

public class Agenda {
    public static void main(String[] args) {

        for(DiasSemana dia : DiasSemana.values()) {
            System.out.println("Valor: " + dia);
            System.out.println("Extenso: " + dia.extenso() + "\n");
        }

    }
}

A saída é:

Valor: SEGUNDA
Extenso: segunda-feira

Valor: TERCA
Extenso: terça-feira

Valor: QUARTA
Extenso: quarta-feira

Valor: QUINTA
Extenso: quinta-feira

Valor: SEXTA
Extenso: sexta-feira

Valor: SABADO
Extenso: sábado

Valor: DOMINGO
Extenso: domingo

Bom galera, foi uma passadinha rápida por aqui para postar algo. Até mais, obrigado pela visita, click nos patrocinadores :) e comentários.

sexta-feira, junho 01, 2007

Palestra sobre Hibernate e Jboss SEAM

Ontem fui a duas palestras na Targettrust, uma delas sobre Hibernate e a outra sobre o Jboss Seam.

Sai de lá me perguntando: porque eu fui? :) Com um monte de coisas que eu preciso estudar para finalmente marcar minha prova de certificação agora fiquei ansiando por aprender mais sobre o SEAM.

Muito boa a palestra, pena que teve seu tempo drasticamente encurtado mas mesmo assim muito legal.

O material está no blog do autor: http://www.juliocsmac.blogspot.com.

Bom, mais além eu irei escrever sobre o SEAM e tal...

Por hora é isso, a vida ta corrida! :P

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

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