quarta-feira, 26 de dezembro de 2012

domingo, 23 de dezembro de 2012

Vamos falar de servlets

Quando estamos aprendendo Java nos deparamos com servlets.
  • O que é um servlet?
  • Por que precisamos de servlets?
  • Qual o uso de um servlet?
  • Qual o ciclo de vida de um servlet? O que é este tal ciclo de vida?
No vídeo abaixo tendo esclarecer estas dúvidas. Você pode assistir aqui ou no YouTube (eu prefiro a segunda opção - a imagem é maior).



No próximo post vamos fazer o famoso OlaMundoServlet.java no Netbeans onde a gente poderá ver o funcionamento com mais detalhes.

sábado, 22 de dezembro de 2012

Criando caixas de diálogo - Parte I

Uma janela de diálogo é uma janela que é aberta sobre outras para transmitir informações (mensagens, erros, alertas) ou para solicitar uma entrada de dados. Diálogos podem ainda apresentar imagens, árvores de diretórios, dispositivos locais, uPnP ou de rede.
 
Diversos componentes de Swing podem ser instanciados para criar um diálogo, a forma mais simples é pela classe JOptionPane. Podemos utilizar ainda JDialog, ProgressMonitor, JColorChooser, JFileChooser etc.

Toda janela de diálogo é dependente de um componente Frame, de tal forma que se este Frame for destruído também as janelas de diálogo a ele vinculados. Se for minimizado, as janelas de diálogo também o são. Ao ser restaurado o Frame, os diálogos abertos reaparecem.


Uma classe JDialog herda o comportamento da classe java.awt.Dialog. Esta classe pode ser modal e quando esta é apresentada na tela, esta janela bloqueia as entradas dos usuários em todas as outras janelas da tela. JOptionPane cria diálogos que são modais, por default. Para criar um diálog não modal, devemos utilizar a classe java.awt.JDialog diretamente.

Vamos focar no JOptionPane

Para criar diálogos simples, podemos utilizar um dos diversos métodos showAlgumaCoisaDialog do JOptionPane. O JOptionPane fornece uma série de métodos estáticos que ao serem invocados criam caixas de diálogos simples.

Os métodos disponíveis são:
  • showMessageDialog: mostra um diálogo simple com botões de confirmação.
  • showConfirmDialog: mostra um diálogo com botões de confirmação.
  • showOptionDialog: mostra um diálogo customizado, podendo conter uma mensagem de texto, uma coleção de componentes e uma variedade de botões.
  • showInputDialog: mostra um diálogo que permite ao usuário digitar uma resposta.

showMessageDialog

Vamos ver alguns exemplos:

JOptionPane.showMessageDialog(this,
  "Este é um exemplo de diálogo simples");

 


JOptionPane.showMessageDialog(this,
  "Este é um exemplo de diálogo simples.",
  "Mensagem de erro",
  JOptionPane.ERROR_MESSAGE);



JOptionPane.showMessageDialog(this,
  "Este é um exemplo de diálogo simples.\nEquivale ao primeiro exemplo",
  "Mensagem de informações",
  JOptionPane.INFORMATION_MESSAGE);
 


 

 JOptionPane.showMessageDialog(this,
  "Este é um exemplo de diálogo simples.",
  "Mensagem de aviso",
  JOptionPane.WARNING_MESSAGE);



JOptionPane.showMessageDialog(this,
  "Este é um exemplo de diálogo simples.",
  "Mensagem de pergunta",
  JOptionPane.QUESTION_MESSAGE);

 
  
JOptionPane.showMessageDialog(this,
  "Este é um exemplo de diálogo simples.",
  "Mensagem simples",
  JOptionPane.PLAIN_MESSAGE);
 



JOptionPane.showMessageDialog(this,
  "Este é um exemplo de diálogo simples.",
  "Mensagem simples com ícone",
  JOptionPane.PLAIN_MESSAGE,
  new ImageIcon( ClassLoader.getSystemResource("imagens/middle.gif") )

);


showConfirmDialog 

Vamos ver alguns exemplos:

JOptionPane.showConfirmDialog(this,
  "Este é um exemplo de diálogo simples");




JOptionPane.showConfirmDialog(this,
  "Este é um exemplo de diálogo com Sim/Não.",
  "Mensagem de input",
  JOptionPane.YES_NO_OPTION);
 




JOptionPane.showConfirmDialog(this,
  "Este é um exemplo de diálogo com Sim/Não/Cancelar.\n"+

  "Equivale ao primeiro exemplo de Input",
  "Mensagem de input",
  JOptionPane.YES_NO_CANCEL_OPTION);
 



JOptionPane.showConfirmDialog(this,
  "Este é um exemplo de diálogo simples.",
  "Mensagem de input",
  JOptionPane.OK_CANCEL_OPTION);
 



JOptionPane.showConfirmDialog(this,
  "Este é um exemplo de diálogo simples.",
  "Mensagem de input",
  JOptionPane.YES_NO_OPTION);
 



JOptionPane.showConfirmDialog(this,
  "Este é um exemplo de diálogo com aviso.",
  "Mensagem de input",
  JOptionPane.YES_NO_OPTION,
  JOptionPane.WARNING_MESSAGE);


 
No próximo post mostro como fazer o programa que gera as telas acima.



quarta-feira, 19 de dezembro de 2012

Classe interna anonima


Vamos ver agora a criação de uma classe interna anônima ... é isto mesmo que você está pensando. Esta classe tem todas as características de uma classe interna, somente ela não é nomeada.

Para tornar o nosso exemplo mais completo vamos criar uma interface. Por quê você vai me perguntar! Porque normalmente as classes anônimas são criadas a partir de definições de interfaces como por exemplo os listeners do swing.

Nossa interface define um atributo privado, que fica exposto somente pelo método getValor(). Este atributo recebe seu valor na construção da classe como podemos ver no construtor.



Como criamos a classe anônima? Percebam o comando

 return new InterfaceExemploClasseAnonima(i) { ...

Estamos chamando o construtor da interface, como temos um método abstrato temos que defini-lo também. É por isto que definimos o método f(). Caso esta definição não fosse feita, o compilador daria erro.

Você percebeu que não definimos o nome da classe? É por isto que chamamos de classe anônima. Um exemplo comum é apresentado no extrato de código abaixo para criar um ActionListener como uma classe anônima:


    //utilizando classe interna anonima
    myBotao.addActionListener(

      new ActionListener() {
        public void actionPerformed(ActionEvent e) { frame.toFront(); }
    });
O resultado de rodarmos a nossa classe de exemplo é

terça-feira, 18 de dezembro de 2012

Classes internas - outro exemplo


Vamos continuar a explorar este tema das classes internas. No nosso exemplo temos agora duas classes internas Conteudo e Destino. Note que podemos acessar seu conteudo a partir de EncomendaCorreio2.

A classe Conteudo utiliza um atributo estático para gerar o id do conteúdo. Como id pertence a classe EncomendaCorreio2, é criada com valor zero, e cada classe Conteudo criada incrementa este valor de 1. O valor que o atributo estava na criação do Conteudo é armazenado como se fosse uma identificação do conteudo. Assim temos um valor diferente a cada construção de Conteudo.

O método envio() de EncomendaCorreio2, cria uma instância para Conteudo e Destino que são armazenadas em atributos privados das instâncias de EncomendaCorreio2.

Note que é possível ter acesso as classes interna e até criá-las, mas neste caso devemos utilizar a sintaxe ClasseMae.ClasseInterna como vemos no final do método main.


Rodando, temos:


domingo, 16 de dezembro de 2012

Classes internas

Uma member class é uma classe que é declarada como não estática dentro de uma outra classe (a que a member class pertence). É o equivalente a um atributo primitivo de uma classe.

Desta forma uma classe membro é associada a uma instância da classe que a contém, o que implica que o código da classe membro tem acesso a todos os atributos da instância e também aos métodos, mesmo a aqueles que foram declarados como private.

Uma classe membro pode receber qualquer um dos três modificadores de visibilidade possíveis (public, private ou protected). Se nenhum dos três for explicitado, a visibilidade será para o pacote. Exatamente igual a qualquer outra classe.

Existem algumas regras para criar uma classe membro:
  • ela não pode ter o mesmo nome da classe que a contém nem do pacote
  • não pode conter atributos, métodos ou classes estaticas (declaradas com o modificados static)
  • não podem ser interfaces
Vamos ver um exemplo
 O resultado de algumas rodadas é:

Vamos ver uma nova classe. Neste exemplo abaixo criamos uma classe com um escopo bastante limitado... somente dentro da cláusula THEN.

Na primeiro compilação abaixo, retirei o comentário que tenta criar uma nova instância da classe BuscaPacote fora do escopo para podermos ver o erro que ocorre. Note que o compilador retorna que não acha a classe (o que era de espera já que afinal ela está definida em outro escopo).

Comentando novamente, é possível compilar e ao rodar temos o retorno de getID().


sábado, 15 de dezembro de 2012

Finalização de classes

Este é o processo inverso a construção que é feito pelo método construtor da classe.  Em Java não vemos falar muito disto, como vemos por exemplo em C. A máquina virtual Java provê um mecanismo denominado garbage collector (coletor de lixo) cuja função é liberar a memória quando um objeto não é mais utilizado. Assim em Java não nos preocupamos em liberar memória, este processo é feito "por baixo dos panos" para nós.

O processo de garbage collector é um processo de baixa prioridade que roda em background (thread de baixa prioridade), então ele realiza suas atividades quando não existe muita coisa acontecendo no seu programa, o que para a maioria dos programas é verdade muitas vezes, pois o programa fica esperando durante muito tempo um comando do usuário.

Você poderia pensar então que pode acontecer horas que rodar somente quando o programa está quase inativo é uma forma ruim, pois se estivermos realizando cálculos intensos com grande movimentação de memória poderíamos ter uma situação de precisar de mais memória e esta ainda não ter sido liberada pelo garbage collector. Você está certo e o pessoal do Java pensou nisto também. Quando a memória vai ficando muito baixa, a thread que roda o garbage collector recebe alta prioridade para permitir a liberação de memória que pode ser essencial para podermos rodar nossos programas.

Se olharmos estrutura do objeto Object vemos que ele possui um método finalize

protected void finalize()
                 throws Throwable

Este método provê a finalização do objeto. Neste caso o garbage collector automaticamente libera a memória usada pelo objeto em questão. Normalmente sobrepomos este método (criando o nosso próprio) para liberar algumas coisas que o garbage collector pode ficar sem saber que tem que liberar como por exemplo handler de arquivos abertos ou de conexões de rede.

Diferente do construtor, somente podemos ter um finalize() por classe e o formato dele é o apresentado acima. Note que ele pode gerar algum tipo de exceção.

Vamos pegar emprestado uma classe que já fizemos antes:


Note que chamamos o método da superclasse.

Existem 4 pontos importantes que tenho que apresentar para vocês:
  1. se um objeto tem um finalize(), este método é chamado logo antes do objeto não mais poder ser utilizado, mas logo antes do garbage collector liberar a memória que ele utiliza.
  2. o Java não dá qualquer garantia sobre quando e em que ordem ocorrerá a limpeza pelo garbage collector. Isto significa que se você precisa liberar recursos em uma determinada ordem, você deve fazer isto explicitamente no seu código e não deixar isto para o garbage collector.
  3. o interpretador Java pode sair sem realizar a limpeza completa, desta forma alguns finalize() nem mesmo serão chamados. Se você quiser garantir isto, deve chamar o método Runtime.addShutdownHook. Isto permite que seu código de finalização seja rodado antes do interpretador fechar.
  4. o objeto não é imediatamente liberado da memória ao chamarmos finalize().

sexta-feira, 14 de dezembro de 2012

O que é uma "inner class"?

"Inner class" é uma classe que é inserida dentro de outra classe, denominada "outer class". Vamos ver um exemplo

Note que temos uma classe definida dentro de ClasseExterna. Um objeto desta classe é instanciado dentro do método apresentaStrings() e com isto conseguimos obter como saídas as duas strings.


Você deu uma olhada nos arquivos que são gerados pelo javac?


A classe interna pode ser referenciada pela classe externa, porém fica encapsulada dentro dela. Os arquivos bytecode começam com o nome da classe ClasseExterna.

Existem duas variações para classe interna:
  • você pode declarar a classe interna dentro do corpo de um método e neste caso temos o que chamamos de "local inner class"; ou
  • você pode declarar a classe interna dentro do corpo do método (semelhante ao modelo anterior), só que sem nomear esta classe interna. Neste caso temos o que chamamos "anonymous inner class"
Uma classe interna pode receber os modificadores:
  • private
  • public
  • protected
de acordo com o tipo de restrição de acesso que você deseja para a classe interna da mesma forma que você faria para qualquer outra classe.

Clonando um objeto II

Oi Pessoal,


Deixem-me consertar dois erros:
  1. esqueci de colocar na postagem anterior a classe Endereco
  2. vou apresentar uma variação melhor do primeiro exemplo para vocês verem como a clonagem funcionou

Vamos a classe
Normalmente eu encapsularia os atributos porém neste exemplo, só para ficar mais fácil deixei todos eles públicos.

No exemplo do post anterior, não ficou muito explícito que o campo interno representado pelo objeto Endereco tenha sido clonado corretamente. Por isto fiz uma variação da classe Exemplo criando Exemplo3.java.

Em Exemplo.java a alteração do endereço era feita em func2 mediante a linha

func2.endereco = new Endereco("Rua do Amendoim, 101", "Belo Horizonte", "MG", "31234-876");

como esta linha cria um novo objeto não dava para perceber se realmente a clonagem havia criado um novo objeto Endereco para func2 ou se a linha acima estava substituindo uma referência do objeto Endereco de func1 pelo que estava sendo criado.

Em Exemplo3.java vemos que não é criado um novo objeto Endereco, alteramos estado em func2 e cidade em func1. Veja na saída que somente estes valores foram alterados.


 Espero que tenha ficado mais claro agora.

Clonando um objeto

De forma geral quando falamos em clonagem, estamos querendo dizer que estamos querendo obter uma cópia do objeto original. A classe Object possui um método denominado .clone() que cria e retorna uma cópia do objeto em questão.

O que vamos ver aqui é que o que se quer dizer como cópia não é necessariamente o que poderíamos esperar. Para que este método funcione, é necessário que o objeto implemente a interface Cloneable. Se ele não implementar é gerada uma exceção CloneNotSupportedException. Todos os arrays implementam esta interface.

Esse método cria uma nova instância do objeto e inicializa todos os campos com o mesmo conteúdo dos respectivos campos. Os conteúdos dos campos não são clonados. A documentação do Java caracteriza esta cópia como sendo "shallow copy". Não é uma "deep copy". Com isto queremos dizer que se a classe contem somente campos primitivos ou referência para objetos imutáveis, o objeto clonado será completamente clonado.

Como assim?

Exemplo 1)
Class Classe1 implements Cloneable {
   String nome;
   int inteiro;
   boolean boleano;
}

public Class
Classe1 c1 = new Classe1();
c1.nome = "nome original";
c1.inteiro = 1;
c2.booleano = true;
Classe1 c2 = c1.clone();
c2.inteiro = 2;
System.out

Campos mutáveis (como classes internas) que estão dentro da estrutura ("deep") do objeto ao serem clonados, não são criados novos objetos, somente é copiada a referência, portanto podemos ter comportamento que podem parecer inesperados como no exemplo abaixo:

Exemplo 2)
Class Campo {
   String campo1;
   boolean campo2;
}

class Classe2 implements Cloneable {
   String nome;
   int inteiro;
   boolean boleano;
   Campo campo;  
}

Classe2 c1 = new Classe1();
Classe2 c2 = c1.clone();
c1.campo.campo1 = "novo valor"

Para resolver isto temos que tratar estes objetos, criando clones deles também.

Vamos ver um exemplo, primeiro fazendo tudo certo, isto é, implementando "deep cloning" - copiando os atributos e os objetos encapsulados. Cada exemplo tem duas classes: uma funcionario que será clonada e outra que gera o exemplo.

Criei um objeto func1, clone este objeto para func2. Alterei os campos e consigo ver que os dois são independentes. A saída de Exemplo é:


Vamos ver agora uma implementação onde não foi clonado o objeto interno explicitamente.

 Vamos ver o que acontece se tento alterar o endereço de fun2. Veja o resultado da cidade para func1 e func2:
Alterei func2 e o resultado apareceu em func1. Por quê?
Porque como o objeto interno não é clonado, somente a referência do objeto é clonada, o que significa que o objeto endereco de func1 e func2 são os mesmos. Uma alteração em um reflete no outro.

 

terça-feira, 11 de dezembro de 2012

Uma alternativa para converter enum em string

Em um post anterior sobre classe do tipo Enum utilizamos diversas @Override para realizar as conversões da tipo enumerado para string. Vamos testar uma outra variação para conseguirmos este mesmo resultado.

No post anterior criamos um Override para cada toString() de cada valor enumerado. Agora vamos criar um construtor para o tipo, fazer o Override do método toString() da classe e criar cada valor passando a string que desejamos que apareça.

Nosso código ficará portanto:

O que estamos fazendo?
  1. criamos um construtor privado para atribuir ao valor enumerado uma String que é nomeDia
  2. sobrepomos o método default toString() para que seja retornado o valor que está em nomeDia
Pronto. Está feito!

Por que isto funciona? Na verdade temos que entender que estamos fazendo 2 coisas no código acima. A primeira é definir uma classe DiasDaSemana que tem um construtor como qualquer outra classe e um método toString. Depois temos que entender que criamos 7 instâncias (objetos) desta classe. Uma para cada valor enumerado. Cada objeto criado é uma enumeração, possui um campo privado denominado nomeDia e nele é armazenado o valor que foi passado no construtor.

Temos que criar uma classe de teste, que chama DiasDaSemana. Basicamente vamos somente dar saída na tela dos valores:

O resultado como esperado é:

Usando switch...case

Uma das estrutura condicionais bastante utilizada em programação java (C, C++ etc) é o switch. O switch verifica uma variável, compara o valor desta variável com os indicados nas cláusulas case. Os cases são as possibilidades de resultados que são obtidos por switch. Caso algum case seja igual ao valor contido na variável, as instruções deste bloco case são executadas.

A estrutura do switch é:

switch (variável) {
    case valor1 :
        Código a ser executado caso valor1 seja igual a da variável
    case valor2 :
        Código a ser executado caso valor2 seja igual a da variável
   case valor3 :
        Código a ser executado caso valor3 seja igual a da variável   
}

Até a versão 6 do Java, switch tratava os tipos primitivos de dados: byte, short, char e int. Agora é possível trabalhar com classes enumeradas e String.


 O resultado quando rodamos esta classe é:

O que mais devemos perceber com relação a utilização do switch/case?
  1. a sintaxe exige que depois do case exista um valor
  2. entre os parênteses depois de switch deve estar uma variável pura, isto é, não podemos colocar neste local uma condicional do tipo (variavel1 > 0)
  3. para marcar o fim do bloco de execução de um case devemos colocar no final do bloco a palavra reservada break
  4. como o switch/case pode ter várias possibilidades, veja no nosso caso, que a variável utilizada é um inteiro e este tipo de variável pode assumir muito mais valores que de 1..7. Utilizamos para tratar estes casos com uma cláusula default. O bloco definido por default é sempre executado quando nenhum dos testes case programados é verdadeiro. Por convenção ele é colocado ao final das condições.

Vamos agora fazer uma variação da classe que testamos. Chamaremos de Exemplo2.java


Note que mantive o método converte que agora estou chamando de toString() e criei um novo método toInt() que faz o inverso de toString().

Este método tem duas coisas interessantes:
  1. utiliza switch ... case com valores do tipo String
  2. utilize String.toLowerCase() para colocar todas as letras em minúsculas e deixar o nosso código um pouco mais genérico.

Vamos compilar e rodar agora a nova classe. No meu caso tenho que trocar para o Windows, pois não tenho Java 7 no linux.
Note que gravo diaStr o valor "Domingo" que é passado para toInt(diaStr). Com isto o switch/case interno pode recodificar a String em um inteiro.

segunda-feira, 10 de dezembro de 2012

Como obter o ContentType em uma chamada HTTP

Neste post vemos como obter o tipo MIME de um objeto de uma página web. Vamos utilizar neste exemplo a página do Google e a logo do Google

O processo de solicitação de uma página ou do logo, você já viu no post sobre busca de página web via GET. A novidade aqui é a utilização da classe org.apache.http.entity.ContentType  que permite capturar o valor de Content-Type da entidade (no nosso caso HttpEntity) ou retorna um valor default se nada foi explicitamente especificado. Devemos ficar atentos ao utilizar este resultado pois ContentType.getOrDefault() não faz qualquer tentativa de tentar validar o tipo do MIME.

Vamos ao nosso código:

Este programa para funcionar tem que possuir algumas diferenças nas bibliotecas com relação ao nosso projeto original de acesso via GET. A classe ContentType só existe a partir da versão 4.2 de org.apache.http.entity.



A saída deste programa é:

domingo, 9 de dezembro de 2012

Como obter a resposta HTTP como string

Neste exemplo continuo utilizando a biblioteca da Apache, denominada HttpComponents. Vamos agora verificar um método mais fácil de refazer o nosso exemplo anterior, isto é, vamos ler uma página e retornar como uma string.

Neste caso não iremos mais utilizar aqueles readLine(). Você irá notar que o processo até obter a página ( getEntity() ) é igual. Utilizamos agora uma classe adicional que retorna a resposta diretamente em uma String: EntityUtils.toString(). Este método lê o do objeto HttpEntity e retorna este conteúdo como uma String. A conversão utilizará o set de caracteres do objeto Entity.

Vamos ao exemplo do código:

Você precisa ter acrescentado as mesmas bibliotecas do post anterior.

sexta-feira, 7 de dezembro de 2012

Convertendo uma Collection em String

Muitas vezes precisamos realizar coversões em estruturas de dados do Java como Arrays e Sets para um formato que podemos manipular como ou enviar para a tela como String.

Existem várias formas de realizar estas conversões:

a) podemos fazer um loop utilizando um Iterator, ir acumulando o valor em uma String e colocando o caracter separador. Com isto é necessário fazer algumas verificações como por exemplo checar para que o último elemento não receba o separador.

b) utilizar classes prontas que realizam este serviço para você como por exemplo Springsource community. Se olharmos no pacote encontramos uma classe util denominada org.springframework.util.StringUtils.

Temos a disposição diversos métodos úteis que estão documentados na API:
  • static String collectionToCommaDelimitedString(Collection coll)
  • static String collectionToDelimitedString(Collection coll, String delim)
  • static String collectionToDelimitedString(Collection coll, String delim, String prefix, String suffix)
  • static Set commaDelimitedListToSet(String str)
  • static String[] commaDelimitedListToStringArray(String str)
  • static String[] delimitedListToStringArray(String str, String delimiter)
  • static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete)
A saída do programa é: