26 de outubro de 2011

Lucene, o motor de busca textual

Lucene é um framework de alto desempenho para busca textual feito em Java. Uma das características marcantes dele é a integração com Hadoop, um framework para computação distribuida, que possui, dentre outros, um MapReduce e um sistema de arquivos distribuido HDFS.

Imagine o seguinte cenário: Seu usuário deseja criar um modulo de gerenciamento de artigos e também expó-los na Internet. As informações do artigo são: título, autor e o contéudo. Normalmente cada artigo desses contém cerca de 1500 palavras e o usuário poderá buscar pelo conteudo desses artigos. Suponha que há 1 milhão e meio de artigos para serem cadastrados, o simples uso de um banco de dados e o operador LIKE '%palavra%' é inviável. E aí que entra um bom framework de busca textual, usá-lo passa ser a solução mais tranquila e viável. Além de trazer velocidade, também traz outras características nas buscas que dificilmente fariamos codificando tudo do zero.

Há vários termos usados na terminologia do framework, os principais são: Documento, Campo, Directório, Indexador, Pesquisador, Analisador e Termo.

Documento - é o conjunto de dados que você deseja indexar, por ex. título, conteudo e autor formam o documento artigo, pode ser visto como um objecto no lucene é visto como Document.

Campo - é o dado, identificado, que pode ser analogo a um campo de uma tabela ou uma propriedade de um objecto no lucene é visto como Field.

Directório - conceito abstrato que denota um local para guardar os índices no lucene é visto como uma interface Directory, que possui diversas implementações DbDirectory, FSDirectory, JEDirectory, RAMDirectory.

Indexador - é o responsável por indexar os documentos num directorio no lucene é visto, geralmente, como IndexWriter.c

Pesquisador - responsável por pesquisar uma Query no diretorio de índices, no lucene é visto como Searcher.

Analisador - actua como um filtro e faz uma pré-avaliação do que pode ser indexado ou não, no lucene há uma lista de vários analisadores.

Termo - pode ser visto como objecto que pode ser usado como parametro da pesquisa, composto pelo nome do campo e o valor a ser pesquisado, no lucene é visto como Term.

Quando se faz uma pesquisa por documentos no Lucene podemos utilizar de alguns operadores (+, -, AND, NOT, OR, * e etc.) juntamente com o termo pesquisado ou apenas pesquisar uma frase completa.
Exemplo : termo
Consequência: Irá pesquisar a palavra "termo" nos documentos indexados.

Exemplo : termo OR palavra ( == termo palavra)
Consequência: Irá pesquisar "termo" ou "palavra" nos documentos indexados.

Exemplo : +termo +palavra ( == termo AND palavra)
Consequência: Irá pesquisar "termo" e "palavra" nos documentos indexados.

Exemplo : campo:termo
Consequência: Irá pesquisar "termo" no campo "campo" nos documentos indexados.

Exemplo : +manutd +java -manager
Consequência: Irá pesquisar documentos que contenham manutd e java e não tenha manager.

Exemplo : "termo exacto"
Consequência: Irá pesquisar documentos que contenham exactamente "termo exacto".

Exemplo : java*
Consequência: Irá pesquisar documentos que contenham palavras que começem com java (javadb, javanet...).

Exemplo : java~
Consequência: Irá pesquisar documentos que contenham palavras similares a java como por ex. lava, jaba...

4 de outubro de 2011

Humor - Como e o que a minha mãe ensinou-me!


Minha mãe ensinou a VALORIZAR O SORRISO...
"ME RESPONDE DE NOVO E EU TE PARTO OS DENTES!"

Minha mãe me ensinou a SER RECTO...
"EU TE AJEITO NEM QUE SEJA NA PANCADA!"


Minha mãe me ensinou a DAR VALOR AO TRABALHO DOS OUTROS...
"SE VOCÊ E SEU IRMÃO QUEREM SE MATAR, VÃO LÁ FORA. ACABEI DE LIMPAR A CASA!"


Minha mãe me ensinou LÓGICA E HIERARQUIA... 
"PORQUE EU DIGO QUE É ASSIM! PONTO FINAL! QUEM É QUE MANDA AQUI?"


Minha mãe me ensinou o que é MOTIVAÇÃO... 
"CONTINUA CHORANDO QUE EU VOU TE DAR UMA RAZÃO VERDADEIRA PARA VOCÊ CHORAR!"


Minha mãe me ensinou a CONTRADIÇÃO... 
" FECHA A BOCA E COME!"

Minha Mãe me ensinou sobre ANTECIPAÇÃO... 
"ESPERA SÓ ATÉ SEU PAI CHEGAR EM CASA!"

Minha Mãe me ensinou sobre PACIÊNCIA... 
"CALMA!... QUANDO CHEGARMOS EM CASA VOCÊ VAI VER SÓ..."


Minha Mãe me ensinou a ENFRENTAR OS DESAFIOS... 
"OLHE PARA MIM! ME RESPONDA QUANDO EU TE FIZER UMA PERGUNTA!" 


Minha Mãe me ensinou sobre RACIOCÍNIO LÓGICO...
"SE VOCÊ CAIR DESSA ÁRVORE VAI QUEBRAR O PESCOÇO E EU VOU TE DAR UMA SURRA!"


Minha Mãe me ensinou sobre o REINO ANIMAL... 
"SE VOCÊ NÃO COMER ESSAS VERDURAS, OS BICHOS DA SUA BARRIGA VÃO COMER VOCÊ!"


Minha Mãe me ensinou sobre GENÉTICA... 
"VOCÊ É IGUALZINHO AO SEU PAI!"


Minha Mãe me ensinou sobre minhas RAÍZES... 
"ESTAS A PENSAR QUE NASCESTE NUM BERÇO DE OURO?" 

Minha Mãe me ensinou sobre a SABEDORIA DE IDADE... 
"QUANDO VOCÊ TIVER A MINHA IDADE, VOCÊ VAI ENTENDER."


Minha Mãe me ensinou sobre JUSTIÇA... 
"UM DIA VOCÊ TERÁ SEUS FILHOS, E EU ESPERO QUE ELES FAÇAM O MESMO QUE VOCÊ FAZ PARA MIM! AÍ VOCÊ VAI VER O QUE É BOM!"


Minha mãe me ensinou RELIGIÃO... 
"MELHOR REZAR PARA ESSA MANCHA SAIR DO TAPETE!"

Minha mãe me ensinou CONTORCIONISMO... 
"OLHA SÓ ESSA ORELHA! QUE NOJO!"

Minha mãe me ensinou DETERMINAÇÃO...
"VAIS FICAR AÍ SENTADO ATÉ COMER TODA COMIDA!"


Minha mãe me ensinou habilidades como VENTRÍLOQUO...
"NÃO RESMUNGUE! CALA ESSA BOCA E ME DIGA POR QUE É QUE VOCÊ FEZ ISSO?"

Minha mãe me ensinou a ESCUTAR ...
"SE VOCÊ NÃO ABAIXAR O VOLUME, EU VOU AÍ E PARTO ESSE RÁDIO!"


Minha mãe me ensinou a TER GOSTO PELOS ESTUDOS... 
"SE EU FOR AÍ, E VOCÊ NÃO TIVER TERMINADO A TAREFA, VOCÊ JÁ SABE!..."

Minha mãe me ajudou na COORDENAÇÃO MOTORA... 
"JUNTA AGORA ESSES BRINQUEDOS!! PEGA UM POR UM!!"

Minha mãe me ensinou os NÚMEROS...
"VOU CONTAR ATÉ DEZ. SE ESSE VASO NÃO APARECER VOCÊ LEVA UMA SURRA!"

Tu és a razão pelo o que hoje sou, e tenho...Muito obrigado, Mãe!!!

Como instalar o Windows a partir de uma pendrive


Se por alguma razão você quer, ou precisa instalar o Windows 7 a partir de uma pendrive (um Netb sem drive de DVD, por exemplo), o único requisito necessário, é que a BIOS da máquina suporte boot pela drive USB.


Procedimentos para preparar a pen-drive:


Antes de começar, insira a pen-drive na porta USB


1 - Abra o prompt de comando (Iniciar >> All Programs >> Acessories >> Command Prompt).


2 – Digite os comandos abaixo, sempre pressionando Enter após cada um:


1. Diskpart (Uma nova janela será aberta, espere até o cursor aparecer)


2. List Disk


3. Select Disk 1 (substitua o 1 pelo número referente a seu pendrive)


4. Clean


5. Create partition primary 


6. Active


7. Format fs=fat32 quick


8. Assign


9. Exit


10 - Agora, abre o DVD do Windows, e copie todo o seu conteúdo para a pendrive. 


Agora basta colocar a seu pendrive no computador desejado, iniciar o sistema por ele, e fazer a instalação.

Java 7: Modificações na Linguagem, detalhes e exemplos


VIA: [http://www.infoq.com]


O JDK 7 é certamente uma das grandes novidades no universo Java. São muitas as modificações em relação à versão anterior, que podem ser divididas nas seguintes categorias: Máquina Virtual, Linguagem, Class Loader, Internacionalização, I/O e Rede, Segurança e Criptografia, JDBC, Camada Cliente e Gerenciamento (JMX e MBeans)

As mudanças dizem respeito à JSR 334: Small Enhancements to the Java Programming Language, implementadas através do projeto Coin, um subprojeto do OpenJDK.

Separador de dígitos em literais numéricos

Com o objetivo de facilitar a leitura no código de literais numéricos longos, a partir do JDK 7 é possível utilizar o caracter "_" (sublinhado) como separador de dígitos. Dessa forma, um número como 99999999, por exemplo, pode ser escrito como: 99_999_999. Durante a compilação, o sublinhado é ignorado e o número é interpretado normalmente como se o separador não existisse. Apesar de a ideia ser interessante, é possível utilizar declarações que podem mais confundir do que ajudar, tais como:

99_99
9_9_9_9
9_____999

Isso acontece porque a única restrição para o uso do separador de dígitos é de que não seja nem o primeiro e nem o último carácter. Também é possível utilizar o separador em literais numéricos de ponto flutuante (double e float), como por exemplo:

12__3.45___6D
53_333.2397

A classe a seguir mostra como o separador pode ser usado em um programa.

  public class SeparadorLiteraisNumericos {
  public static void main(String[] args) {
 byte b =  1_2_7;
 int v1 = 999_999;
 int v2 = 100_000 - 1_000;
 Integer i1 = new Integer(12_12_12_1);
 Integer i2 = new Integer(1_2_1_2_1_2_1);
 double f = 123_456.3_4_1;

 System.out.printf("O valor de b e': %d\n", b);
 System.out.printf("O valor de v1 e': %d\n", v1);
 System.out.printf("O valor de v2 e': %d\n", v2);
 System.out.printf("i1 e i2 são iguais?: %b\n", i1.equals(i2));
 System.out.printf("O valor de f e': %.4f\n", f);
  }
}

Ao executar esse programa, a seguinte saída é obtida:

  O valor de b é: 127
  O valor de v1 é: 999999
  O valor de v2 é: 99000
  i1 é igual a i2?: true
  O valor de f é: 123456.3410

Literais Binários

Até a versão 6 do Java, era possível trabalhar com literais inteiros definidos como octais, decimais e hexadecimais. A partir da versão 7 também é possível trabalhar com literais binários. Para a grande maioria das aplicações comerciais isso pode não trazer grandes ganhos, mas em sistemas nos quais são frequentes as operações envolvendo bits, isso pode ser realmente útil. A sintaxe da nova declaração é simples, bastando iniciar o literal com 0b (zero e a letra 'b') seguido por uma sequência de 0s e 1s. Por exemplo:

0b1100
0b01
0b1101

Os dígitos são alinhados à direita na área de memória, independentemente do tipo (byte, short, etc), ou seja, 0b11 é igual a 3, 0b101 é igual a 5 e assim por diante.

O código a seguir simula um log de estados de um sensor. Os estados possíveis que o sensor pode assumir são definidos pelos seguintes padrões binários: 01 indica que o sensor está desligado; 10 indica que está ligado e 11 indica que está em alarme. Para simular esses estados foi criado o método lerEstado que devolve aleatoriamente um inteiro com esses valores possíveis de estados além de um valor 0b00 indicando que não foi possível fazer a leitura (SEM_LEITURA). No método main() é executado um laço que lê o estado actual até que seja obtido o valor inválido e imprime uma mensagem informando o estado atual. Nesse programa simples, cada estado é representado por uma constante que depois será utilizada para indexar um array de mensagens.

     public class GerenciadorSensor {
     private static final int SEM_LEITURA   = 0b00;
     private static final int DESLIGADO     = 0b01;
     private static final int LIGADO        = 0b10;
     private static final int ALARME        = 0b11;

   private static final String[] MENSAGENS = {"não disponível", "desligado", "ligado",     "alarme"};

    public static int lerEstado() {
     return (int)(Math.random()*0b100);
  }

 public static void main(String[] args) {
System.out.printf("Os estados possíveis são: %s(%d) %s(%d), %s(%d), %s(%d)\n\n", MENSAGENS[SEM_LEITURA], SEM_LEITURA, MENSAGENS[DESLIGADO], DESLIGADO, MENSAGENS[LIGADO], LIGADO, MENSAGENS[ALARME], ALARME);
int st = lerEstado();
while (st != SEM_LEITURA) {
System.out.printf("O estado do sensor é: %s\n", MENSAGENS[st]);
st = lerEstado();
 }
 }
}

Uma saída possível para esse programa é:

Os estados possíveis são: não disponível(0) desligado(1), ligado(2), alarme(3)

  O estado do sensor é: desligado
  O estado do sensor é: ligado
  O estado do sensor é: desligado
  O estado do sensor é: alarme
  O estado do sensor é: alarme
  O estado do sensor é: desligado
  O estado do sensor é: desligado

Observe que no main(), são utilizadas as constantes de estados (inicializadas com valores literais binários), para acessar as posições do array contendo as mensagens.

E combinando o novo tipo binário com a nova sintaxe de separadores de dígitos, podemos ter:

  private static final int SEM_LEITURA   = 0b0_0;
  private static final int DESLIGADO     = 0b0__1;
  private static final int LIGADO        = 0b1_0;
  private static final int ALARME        = 0b1___1;

Variáveis do tipo String em comandos switch

Uma alteração muito útil na linguagem é que agora podem ser utilizadas Strings em comandos switch. Observe o programa a seguir, que recebe parâmetros de configuração através da linha de comando, e executa acções específicas para cada parâmetro.

public class StringNoSwitch {
 public static void main(String[] args) {
 for (String param : args) {

 switch(param) {

 case "-test":
 System.out.println("O programa está sendo executado em modo teste");
 break;

 case "-silent":
 System.out.println("O programa envia poucas informações na saída padrão");
 break;

case "-verbose":
System.out.println("O programa envia muitas informações na saída padrão");
break;

default:

System.err.printf("Parâmetro %s não reconhecido\n", param);
System.exit(-1);
}
}
}
}

Note que no switch da linha 5 é utilizada uma variável do tipo String para seleccionar entre os vários casos de teste de condição. Apesar dessa ser uma alteração simples, esse recurso simplifica o código evitando uma estrutura complexa composta por varios ifs encadeados.

Inferência na Criação de Objetos de Tipos Genéricos

O suporte para tipos genéricos (ou parametrizados) é certamente um aliado do desenvolvedor, facilitando tanto a codificação quando a depuração. Com esse recurso, como sabemos, é possível informar tipos como parâmetros para classes e interfaces, fornecendo informações adicionais que permitem ao compilador detectar erros em tempo de compilação, que sem o uso dos tipos genéricos seriam detectados somente em tempo de execução.

Apesar das vantagens dos Generics, com esse recurso a linguagem também ganhou em complexidade. Veja um exemplo na classe InferenciaGenerics abaixo:

import java.util.*;
public class InferenciaGenerics {
public static void main(String[] args) {
Map<Integer, Set<Integer>> mapOfIntegers = new HashMap<Integer, Set<Integer>>();
Integer aKey = 10;
Set<Integer> aSet = new HashSet<Integer>();
 mapOfIntegers.put(aKey, aSet);
  }
}

No Java 7 é possível usar uma sintaxe para a criação dos objectos Map e Set acima, através da omissão dos tipos, com uma notação que foi apelidada de diamond:

import java.util.*;
public class InferenciaGenerics {
   public static void main(String[] args) {
     Map<Integer, Set<Integer>> mapOfIntegers = new HashMap<>();
     Integer aKey = 10;   
     Set<Integer> aSet = new HashSet<>();
     mapOfIntegers.put(aKey, aSet);
  }
}

Com essa sintaxe, os parâmetros de tipos usados na construção dos objectos são inferidos a partir dos parâmetros definidos na referência para esse objecto. Ou seja, em uma declaração Tipo<t1, t2, ..., tk> ref = new Tipo<>(), o compilador entenderá que new Tipo<>() deverá ser substituído por new Tipo<t1, t2,..., tk>().

Além disso, também é possível adiar a criação do objecto do tipo HashSet (aSet), fazendo-o na última linha da seguinte forma:

mapOfIntegers.put(aKey, aSet = new HashSet<>());

Neste caso, os parâmetros do tipo são inferidos a partir daqueles usados na declaração da variável aSet. Note que a seguinte sentença não compila:

mapOfIntegers.put(aKey, new HashSet<>()); //gera erro de compilação

Simplificação na Invocação de Métodos Varargs

Em Java, arrays e tipos genéricos não combinam muito bem. Observe o seguinte exemplo:

  import java.util.*;
  public class TesteVarargs {
  public static void main(String[] args) {
  Set<Integer> aSet = new HashSet<Integer>();
  List<Set<Integer>> listOfSets = Arrays.asList(aSet);
 }
 }

Quando o programa acima é compilado com o Java versão <= 1.6 através do comando  javac -Xlint:unchecked Varargs.java, o compilador gera o seguinte warning:

TesteVarargs.java:10: warning: [unchecked] unchecked generic array
creation of type java.util.Set<java.lang.Integer>[] for varargs parameter
List<Set<Integer>> listOfSets = Arrays.asList(aSet);
                                            
Repare, no entanto, que não há nada de errado ou estranho com esse programa. Mas porque o compilador emitiu esse warning? Na verdade, o que acontece é que antes de o compilador gerar o bytecode é feita uma conversão no programa que literalmente modifica a linha 5, que fica assim internamente:

List<Set<Integer>> listOfSets = Arrays.asList(new Set[]{aSet});

Note que nessa conversão o Set usado para construir o array não contém mais a informação de tipo (em Java não é permitida a criação de um array usando generics) o que provoca o warning. Generalizando, esse warning é gerado sempre que é feita a chamada para um método com uma sintaxe do tipo a seguir:

<T> Tipo<T> metodo(T... params)
Aqui T e Tipo são dois tipos que podem ser parametrizados e, na ocasião da chamada do método em questão, as instâncias representadas pelo array params também estão com tipos genéricos. No exemplo apresentado, T é Set<Integer> enquanto que Tipo<T> é List<Set<Integer>>.

Uma forma de evitar esse warning é incluindo a anotação @SuppressWarnings("unchecked") no método, ou na linha imediatamente antes daquela onde o compilador indicou o warning. Apesar de resolver o problema, isso é um tanto inconveniente porque polui o código sem necessidade, visto que a chamada do método não pode gerar problema em relação à tipagem (heap pollution seria o termo usado aqui).

Observe que no exemplo apresentado não há nada que possa ser feito para evitar esse warning, a não ser adicionar a anotação. Assim, seria interessante que em casos desse tipo o compilador pudesse entender que a chamada não pode gerar problema. Para resolver essa situação foi criado no Java 7 a anotação @SafeVarargs.

A função dessa anotação é informar ao compilador que a operação de conversão forçada de arrays com tipos genéricos é segura, ou seja, que não acontecerá o heap pollution. Quando usada na declaração de um método com a sintaxe citada, essa anotação desonera as classes que chamam esses métodos da necessidade de utilizarem @SuppressWarnings. Isso é o que acontece, no JDK 7, com o método asList() da classe Arrays, como é mostrado a seguir, e também com alguns outros métodos da API.

@SafeVarargs
public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}

É importante observar que agora a responsabilidade de informar ao compilador para não gerar o warning é da classe que fornece a implementação e não da classe cliente que a usa.

Gerenciamento Automático de Recursos & Multicatch

Duas novidades que vão facilitar muito a vida do desenvolvedor Java são o gerenciamento automático de recursos e o "multicatch". Utilizaremos um exemplo para mostrar essas novas funcionalidades.

Suponha que precisamos de um programa que primeiro leia um arquivo texto contendo nomes de classes, com um nome por linha incluindo o pacote; e depois para cada linha, carregue e crie um objeto da classe fornecida, usando os metodos Class.forName () e Class.newInstance() da API de Reflection. Suponha também que os devidos tratamentos de erros sejam feitos.

Para fazer a leitura do arquivo seriam normalmente utilizados um FileReader e um BufferedFileReader, mas para esse exemplo foi criada uma classe que especializa BufferedReader, com o objetivo de simplesmente mostrar quando o método close() é chamado. O código dessa classe é apresentado a seguir:

 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.Reader;
  
 public class MyBufferedReader extends BufferedReader {
 public MyBufferedReader(Reader r) {
 super(r);
 }
  
 public void close() throws IOException {
 System.out.println("fechando o BufferedStream");
 super.close();
 }
}

Aqui está a classe responsável por solucionar o problema:

import java.io.FileReader;

public class GerenciadorRecursosMultiCatch {
private static void instantiate(String className) throws Exception {
try {
Class<?> clazz = Class.forName(className);
Object o = clazz.newInstance();
System.out.println(o.getClass().getName());
  
} catch (ClassNotFoundException e) {
System.err.println("Classe nao encontrada: " + className);
throw e;
} catch (InstantiationException e) {
System.err.println("Nao foi possivel instanciar a classe: " + className);
throw e;
} catch (IllegalAccessException e) {
System.err.println("Nao foi possivel instanciar a classe: " + className);
throw e;
}
}

public static void main(String[] args) throws Exception {
MyBufferedReader br = new MyBufferedReader(new FileReader("classes.txt"));
try { 
String line;
while ((line = br.readLine()) != null)
instantiate(line);
} finally {
br.close();
}
}
}

O main() é responsável basicamente por ler o arquivo classes.txt. O conteúdo de cada linha é passado para o método instantiate(), que tentará carregar a classe e criar uma instância.

Suponha que o arquivo classes.txt contenha somente a linha: java.util.ArrayList. Ao executarmos o programa acima, é obtida a seguinte saída:

java.util.ArrayList
fechando o BufferedStream

Caso alguma linha do arquivo classes.txt contenha o nome de uma classe que não exista no Java, como por exemplo: java.util.ArrayList1, a seguinte saída é obtida:

Classe nao encontrada: java.util.ArrayList1
fechando o BufferedStream
Exception in thread "main" java.lang.ClassNotFoundException: java.util.ArrayList1
 at java.net.URLClassLoader$1.run(URLClassLoader.java:202)

Observe no método main() o uso do finally na linha 28. Nele, é chamado o método close() da instância de MyBufferedReader, com o objectivo de liberar os recursos alocados para usar o arquivo classes.txt. Note também que, tanto executando o programa com sucesso quanto em situações de erro, a mensagem: "fechando o BufferedStream" aparece. Ou seja, o finally é executado e os recursos são liberados corretamente em ambos os casos.

Essa abordagem no uso do finally é muito comum quando trabalhamos com acesso a banco de dados, manipulação de arquivos e IO em geral, entre outras situações. São em casos como esses que é necessário que o programa adquira recursos do SO quando necessário e os libere posteriormente.

Para tirar esse trabalho do desenvolvedor, o Java 7 traz o gerenciamento automático de recursos. Observe o código a seguir que demonstra essa funcionalidade no método main(), substituindo o mesmo método do exemplo anterior (classe GerenciadorRecursosMultiCatch):

public static void main(String[] args) throws Exception {
try(MyBufferedReader br = new MyBufferedReader(new FileReader("classes.txt"))) {
String line;
while ((line = br.readLine()) != null)
instantiate(line);
}
}
}

Com a mudança, a declaração e a inicialização do MyBufferedReader são feitas no próprio try. Isso determina que a instância terá seu método close() chamado automaticamente, de forma semelhante àquela obtida quando usamos o finally. Isso certamente evita confusões e erros na hora de liberar recursos.

Mas como o Java sabe quais classes podem ser usadas para fazer esse tratamento? A resposta é que agora existe a interface java.lang.AutoCloseable, com um único método: void close() throws Exception. Com isso, qualquer classe que implementa essa interface pode ser passada para o try, e o método close() será chamado correctamente. Em decorrência da chamada implícita do close(), esse try deve fazer parte de outro try contendo um catch para Exception; ou então o método deve lançar Exception.

Ao executar o programa de exemplo, após a modificação do método main(), será mostrada a mensagem "fechando o BufferedStream", mesmo sem a chamada explícita do método close().

Continuando com o mesmo exemplo, passamos à demonstração do recurso de multicatch, que permite a um catch tratar múltiplas excepções. Dessa forma, quando existem vários catch fazendo um mesmo tratamento para exceções diferentes, é possível juntá-los em um único catch. Utilizando a nova sintaxe no método instantiate(), o trecho relevante do exemplo fica da seguinte forma:

private static void instantiate(String className) throws Exception {
try {
Class<?> clazz = Class.forName(className);
Object o = clazz.newInstance();
System.out.println(o.getClass().getName());
  
} catch (ClassNotFoundException e) {
System.err.println("Classe nao encontrada: " + className);
throw e;
} catch (InstantiationException | IllegalAccessException e) {
System.out.println("Nao foi possivel instanciar a classe: " + className);
throw e;
}
}

Como estávamos fazendo o mesmo tratamento para as exceções InstantiationException e IllegalAccessException, juntamos as duas exceções num só catch. Repare que as exceções são separadas por um carácter pipe, '|'. A sintaxe do multicatch é definida da seguinte forma:

try {
  // código
} catch (Exceção 1 | Exceção 2 | ... | Exceção n variável) {
  // tratamento da excepção
}

Aqui, Exceção 1 | Exceção 2 | ... | Exceção n são exceções (classes que herdam de java.lang.Exception) e variável é a variável na qual será atribuída a instância da exceção que foi lançada por alguma instrução no bloco try. A forma como é feito o tratamento da exceção no bloco exception continua igual ao que era feito antes dessa modificação de sintaxe.

Conclusões

Foram apresentadas as mudanças na linguagem Java que estarão presentes no JDK 7. Essas mudanças foram propostas pelo projecto Coin, um subprojecto do OpenJDK, através da JSR 334. Entre as mudanças propostas, as que podem ser consideradas mais significativas são o suporte a strings na expressão do switch, o gerenciamento automático de recursos e, com o objectivo de reduzir a verbosidade da linguagem, os recursos de inferência de tipos genéricos e o multi-catch. O código fonte dos programas utilizados como exemplo estão disponíveis no Github.

Apesar de o itens apresentados nesse estarem de acordo com o que foi sugerido na versão actual da JSR 334, e também em conformidade com a implementação disponível no OpenJDK, é possível que ainda ocorram pequenas mudanças até a finalização da especificação.

1 de outubro de 2011

Humor - Galo corno!

Humor - Recém-casados


Primeira noite dos recém-casados. Na cama, a mulher diz ao marido:

- Sabe, amor, eu não te disse por vergonha, mas eu não sei fazer completamente nada!

O marido responde:

- Não te preocupes, minha linda! Você tira a roupa, deita sobre a cama e deixa que eu faço o resto!

E ela, suavemente responde:

- Não, amor! - Sexo, eu faço muito bem, desde os 14 anos. O que eu não sei fazer é: lavar, engomar, cozinhar, arrumar a casa...