terça-feira, março 09, 2010

Usando literais binários e separadores de milhar em Java 7

Em Java 7, poderemos usar números binários (embora sejam um pouco extensos), o que facilita a quem precisa codificar máscaras de bits.

Além disso, uma coisa bem mais útil é que podemos agora pôr separadores de dígitos dentro de constantes numéricas.

É bem mais fácil conferir pi = 3.141_592_653_589_793_238_462_643_383_279_5 em vez de 3.1415926535897932384626433832795.

Entretanto, esse suporte a separadores de milhar vale só para o compilador; as rotinas (como Integer.parseInt ou DecimalFormat.parse) não entendem o "_". Isso, provavelmente, é para garantir compatibilidade com programas já existentes.

Uma coisa que sempre me incomodou é que números octais são iniciados por um simples zero, tal como em C/C++. Isso é muito confuso; seria preferível que houvesse um indicador de base (como, digamos, a letra Q. Por exemplo, em vez de 0377, teríamos a constante 0Q377.). Como isso já é uma "pegadinha" antiga da linguagem, eu sugiro que se use sempre um separador, para você tomar cuidado com esse zero inicial. Em vez de usar o número 0377, deveríamos usar 0_377. Mas não sei se uma convenção dessas ajudaria muito ou não.

import java.text.*;

// Requer Java 7 para ser compilada
class NovosLiterais {
    public static void main (String[] args) {
        int cafeBabe = -889275714;
        assert (cafeBabe == 0xCAFEBABE); // hexadecimal
        assert (cafeBabe == 031277535276); // octal
        // 0b introduz um número em notação binária
        assert (cafeBabe == 0b11001010111111101011101010111110); // binário
        // "_" separa os dígitos.
        assert (cafeBabe == 0b1100_1010_1111_1110_1011_1010_1011_1110); // binário
        // Pode-se usar separadores de dígitos em qualquer base
        assert (cafeBabe == 0xCAFE_BABE);
        assert (cafeBabe == -889_275_714);
        assert (cafeBabe == 0_31_277_535_276);
        // Não é preciso pôr os separadores de 3 em 3 ou de 4 em 4. 
        long cnpj = 65_497_745_0001_53L;
        // É possível usar separadores de dígitos mesmo com números de ponto-flutuante
        double pi = 3.141_592_653_589_793_238_462_643_383_279_5;
        double avogadro_constant = 6.022_141_79E+23;
        // Você não pode usar o "_" no início de uma constante, porque aí teríamos
        // um identificador. Ele só pode ser usado dentro de uma constante.
        double _42; // isto é um identificador, não uma constante
        // .parseInt, .parseLong não suportam "_"
 try { 
            long x = Long.parseLong ("CAFEBABE", 16); 
            x = Long.parseLong ("CAFE_BABE", 16);
        } catch (NumberFormatException ex) { ex.printStackTrace(); }
 try { 
            int x = Integer.parseInt ("11001010", 2); 
            x = Integer.parseInt ("1100_1010", 2);
        } catch (NumberFormatException ex) { ex.printStackTrace(); }
        // DecimalFormat.parse também não suporta "_"
        NumberFormat df = DecimalFormat.getInstance();
        try { Number n = df.parse ("123_456"); 
            System.out.println (n); // imprime "123", o que indica que ele não consegue ver além do "_"
        }  catch (ParseException ex) { ex.printStackTrace(); }
    }
}