quarta-feira, 2 de fevereiro de 2011

Testando as novas funcionalidades do JDK 7 - Parte 1

No dia 18/01 foi lançada a primeira release do JDK 7 contendo todas as funcionalidades planejadas para essa versão. Como eu fiquei muito curioso, tive que instalar essa versão e fuçar um pouco só para dar uma descontraída!! Vale citar que essa não é uma versão final, portanto, se você pretende instalar para desenvolver ou mesmo usá-la em ambiente de produção, esqueça....algo sinistro pode acontecer (ok, se mesmo assim você fez isso, conta o resultado pra gente :-)  ).

As modificações dessa versão 7 do JDK em relação à versão anterior foram divididas nas seguintes categorias: Máquina Virtual, Linguagem, Core, Internacionalização, I/O e Rede, Segurança e Criptografia, JDBC, Camada Cliente, Gerenciamento (JMX e MBeans).  Como existem muitas modificações, eu optei por tratar nesse post somente as alterações na linguagem (sintaxe e semântica) e, devido ao meu tempo escasso, resolvi mostrar as novas funcionalidades em dois posts, sendo que o segundo post eu ainda não tenho planejado quando ficará pronto, mas espero que seja em breve então, stay tuned!!!

Bem, chega de blah blah blah e vamos ao que interessa.

1. String na Seleção do switch

Uma alteração interessante e muito útil é 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 ações específicas para cada parâmetro.

public class StringsInSwitch {

  public static void main(String[] args) {
    for (String param : args) {
      switch(param) {
        case "-test": 
          System.out.println("O programa esta sendo executado em modo teste");
          break;
        case "-silent":
          System.out.println("O programa envia poucas informacoes na saida padrao");
          break;
        case "-verbose":
          System.out.println("O programa envia muitas informacoes na saida padrao");
          break;
        default:
          System.out.printf("Parametro %s nao reconhecido\n", param);
          System.exit(-1);
      }
    }
  }
}

Note que no switch da linha 5 é utilizada uma variável do tipo String para selecionar entre os vários casos de teste de condição. Apesar dessa ser uma alteração simples, isso evita aquele monte de ifs encadeados ou então a necessidade de procurar soluções mirabolantes para contornar situações desse tipo.

2. Underscore como separador de dígitos

Não sei se isso pode parecer normal para muitos, mas para mim realmente não é!! A partir do JDK 7 é possível utilizar o caractere "_"  (underscore, underline, grifo, sublinhado, etc, etc, etc) como separador de dígitos em literais  numéricos. Segundo a proposta (leia mais sobre o subprojeto Coin através do link na seção de Links Úteis no final do post), a idéia é criar um mecanismo que possa facilitar a leitura por seres humanos de um número com vários dígitos. Dessa forma, ao invés de escrevermos um número assim: 123456789, podemos escrever 123_456_789. Basicamente, o compilador vai ignorar o underscore e interpretar  o número como se esse caractere não existisse. Até aí, você talvez tenha gostado dessa idéia, mas o problema é que podemos escrever esse mesmo número nos seguintes formatos:

  • 1_2_3_4_5_6_7_8_9
  • 123__45__678__9
  • 12_3456_78_9
  • 12___________________345678______9
Além disso, isso também vale para números de ponto flutuante (double e float), tais como:
  • 12__3.45___6D
Note que o underscore poder ser utilizado livremente em qualquer posição de literais numéricos, exceto na primeira e na última. O programa a seguir apresenta um exemplo de uso do underscore como separador:

public class UnderscoreAsSeparator {

  public static void main(String[] args) {
    int x = 10_000;
    int y = 3_333;
    long l = 123_123_123_123L;
    double f = 123_456.3_4_1;

    System.out.printf("O valor de x e: %d\n", x);
    System.out.printf("O valor de y e: %d\n", y);
    System.out.printf("O valor de l e: %d\n", l);
    System.out.printf("O valor de f e: %.4f\n", f);
    System.out.printf("O valor de x+y e: %d\n", x+y);
  }
}

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

O valor de x e': 10000
O valor de y e': 3333
O valor de l e': 123123123123
O valor de f e': 123456,3410
O valor de x+y e': 13333

3. 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 até não fazer muito sentido, mas em sistemas nos quais são frequentes as operações binárias envolvendo bits e shitfs, isso pode ser uma mão na roda! A sintaxe dessa declaração é muito simples, basta iniciar o literal com 0b (número zero seguido da letra 'b') seguido por uma sequência de 0s e 1s. Por exemplo:

  • 0b1100
  • 0b01
  • 0b1101

Repare que os dígitos são alinhados à direita na área de memória, ou seja,  0b11 é igual a 3.

O código a seguir simula um interpretador de sinais obtidos a partir da leitura do status de uma válvula e imprime o status atual. Os status são formados a partir de padrões de bits, isto é, quando a válvula está fechada o valor binário é 01, quando a válvula está aberta o valor binário é 10 e quando a válvula está em alarme o valor é binário é 11. Para simular os status foi construído o método readStatus que devolve aleatóriamente um inteiro com os valores possíveis de status da válvula. No método main é executado um laço que lê o status atual até que ele seja nulo (NONE) e imprime uma mensagem informando o status atual. Cada status é representado por uma constante que depois será utilizada para indexar um array de mensagens.

public class BitLiteral {
  private static final int NONE   = 0b00;
  private static final int CLOSED = 0b01;
  private static final int OPEN   = 0b10;
  private static final int ALARM  = 0b11;

  private static final String[] MESSAGES = {"NONE", "CLOSED", "OPEN", "ALARM"};

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

  public static void main(String[] args) {
    System.out.printf("The notable statuses are: %s(%d) %s(%d), %s(%d), %s(%d)\n\n",
      MESSAGES[NONE], NONE, MESSAGES[CLOSED], CLOSED,
      MESSAGES[OPEN], OPEN, MESSAGES[ALARM], ALARM);

    int st = readStatus();
    while (st != NONE) {
        System.out.printf("Valve state is: %s\n", MESSAGES[st]);
        st = readStatus();
    }
  } 
}

Observe que no método main são utilizadas as constantes de status (inicializadas através da notação binária) para acessar as posições do vetor contendo as mensagens. No final das contas, o mesmo raciocínio utilizado para literais octais, hexa e decimais também é aplicado aos binários.

Só para complementar essa discussão sobre literias binários, também é possível utilizar o underscore como separador de dígitos:

private static final int NONE   = 0b0___0;
private static final int CLOSED = 0b0_1;
private static final int OPEN   = 0b1___0;
private static final int ALARM  = 0b1_1;

Conclusão e Cenas do Próximo Capítulo

Nesse post foram apresentadas as seguintes novas funcionalidades do JDK 7: String na seleção do switch, underscore para separar dígitos em literais e literais binárias. Entre esse itens citados, o que realmente deve agradar mais os desenvolvedores é  a possibilidade de utilizar strings na seleção do comando switch. De qualquer forma, vale a pena ficar atento dessa outras mudanças pois um dia nós poderemos encontrar algo assim em algum código perdido por aí!

No próximo post eu vou comentar sobre a inferência na instanciação de tipos genéricos, as novas formas de tratamento de exceção e também sobre as mudanças em varargs e também outras modificações bacanas que ficaram para o JDK 8.

Isso aí! Agora eu vou ouvir Judas Priest.....até a próxima!

Links Uteis


    O Projeto COIN é na verdade um subprojeto do OpenJDK que tem como objetivo definir mudanças na linguagem Java que serão incorporadas no JDK - nesse caso, os itens apresentados nesse post foram apresentados todos pelo projeto COIN.