JDC Tech Tips (04 de Diciembre de 2001)

Bienvenido a los Consejos Técnicos de la Conexión del Desarrollador Java (JDC), del 4 de Diciembre de 2001. Esta edición cubre:

  • Acceder al Entorno desde Aplicaciones Java.
  • Trabajar con Bases Numéricas.

Estos consejos fueron desarrollados usando Java(tm) 2 SDK, Standard Edition v 1.3

Se puede ver esta edición (en su original en inglés) de los Consejos Técnicos en formato html en http://java.sun.com/jdc/JDCTechTips/2001/tt1204.html

Acceder al Entorno desde Aplicaciones Java

Si has usado mucho los sistemas UNIX o Windows, probablemente estarás familiarizado con las llamadas variables de entorno. Estas variables son un grupo de selecciones que existen fuera de las aplicaciones, pero que están disponibles dentro de estas aplicaciones. Sobre sistemas UNIX, estás variables normalmente están mantenidas por un shell y transmitidas a los programas que invoca este shell. Un ejemplo de variable de entorno sobre un sistema UNIX podría ser:

    HOME=/home/aname

    USER=aname

Podemos acceder a esta variables desde dentro de un programa C usando la función de librería estándard getenv. Dichas selecciones se usan para personalizar una aplicación.

La clases System del paquete java.lang tiene un método getenv para acceder a variables de entorno. Aquí tenemos un simple ejemplo que usa el método:

    public class EnvDemo1 {
        public static void main(String args[]) {
            String s = System.getenv("USER");
            System.out.println(s);
        }
    }

El método getenv está obsoleto, por eso obtendremos un aviso cuando compilamos el programa. También obtendremos una excepción si intentamos ejecutarlo.

¿Por qué este comportamiento? La razón fundamental es simplemente que el concepto de la variables de entorno no es portable. No hay garantía que un sistema operativo dado las soporte, e incluso si lo hace, las selecciones podrían no ser uniformes. Por ejemplo, un sistema Windows particular podría no tener una variable USER, pero tener en su lugar una variable USERNAME. Por eso asumir la presencia de USER en una aplicación Java no funcionará en un sistema que no la soporta.

Si debemos tener acceso a las variables de entorno, hay un par de formas de hacer esto. Podriamos usar el Java Native Interface para acceder a una pequeña función C llamada getenv. Esta aproximación funciona pero no es portable.

Otra aproximación es pasar el valor de la variable de entorno a nuestra aplicación Java cuando ésta es invocada. Aquí tenemos un pequeño programa que ilustra esta técnica:

    public class EnvDemo2 {
        public static void main(String args[]) {
            String s = 
              System.getProperty("localuser");
            System.out.println("localuser = " + s);
        }
    }

Si lanzamos los comandos:

    javac EnvDemo2.java

    java -Dlocaluser=$USERNAME EnvDemo2

El resultado es:

    localuser = username

donde "username" es reemplazado con el valor de la variable de entorno USERNAME de nuestro sistema. Por supuesto, esto asume que nuestro sistema incluye la variable de entorno USERNAME.

Las propiedades Java son las equivalentes Java a las variables de entorno. La bandera -D y la llamada a System.getProperty son un mecanismo para pasar valores de propiedades a una aplicación Java cuando se lanza la aplicación.

Esta aplicación funciona, pero todavía depende de la variable de entorno. Sin embargo hay una forma mejor. En esta aproximación, usamos las propiedades del sistema estándard. Por ejemplo, para obtener el nombre del usuario actual, podemos decir:

    public class EnvDemo3 {
        public static void main(String args[]) {
            String s = 
              System.getProperty("user.name");
            System.out.println(s);
        }
    }

user.name es una de un conjunto de propiedades estándard que están garantizadas que están definidas en nuestro sistema Java. Para obtener una lista de todas las selecciones de propiedades que conoce nuestro sistema local, podemos ejecutar este programa:

    import java.util.Properties;
    
    public class EnvDemo4 {
        public static void main(String args[]) {
            Properties p = System.getProperties();
            p.list(System.out);
        }
    }

En un sistema Windows, parte de la salida debería ser algo similar a esto:

    -- listing properties --
    file.separator=
    java.vendor.url.bug=
            http://java.sun.com/cgi-bin/bugreport...
    sun.cpu.endian=little
    sun.io.unicode.encoding=UnicodeLittle
    user.region=US
    sun.cpu.isalist=pentium i486 i386

Observa que el file.separator está seleccionado a , indicando que este es un sistema Windows en vez de en un sistema UNIX. Las aplicaciones Java deben contar con dichas variaciones del entorno o podrían tener problemas de portabilidad.

Cuando trabajamos con propiedades, hay algunos métodos útiles que podemos usar para simplificar la programación. Aquí tenemos un ejemplo:

    public class EnvDemo5 {
        public static void main(String args[]) {
            Integer size = 
              Integer.getInteger("size");
            System.out.println("size = " + size);
        }
    }

Integer.getInteger es un método que busca una propiedad del sistema y devuelve su valor entero, o null si la propiedad no existe. Por ejemplo, si decimos:

    javac EnvDemo5.java

    java -Dsize=59 EnvDemo5

el resultado es:

    size = 59

Hay otro aspecto interesante de las propiedades. Podríamos personalizar una aplicación pasándole selecciones de propiedades con la opción -D. Sin embargo, también podemos definir nuestro propio fichero de propiedades, y grabar y restaurar un grupo de propiedades con una sola operación. Aquí tenemos un ejemplo de esta técnica. El primer programa se usa para escribir el fichero de propiedades:

    import java.io.*;
    import java.util.Properties;
    
    public class EnvDemo6 {
        public static void main(String args[]) 
                            throws IOException {
            FileOutputStream fos =
                new FileOutputStream("test.prop");
            BufferedOutputStream bos =
                new BufferedOutputStream(fos);
            Properties p = new Properties();
            p.setProperty("key1", "value1");
            p.setProperty("key2", "value2");
            p.store(bos, "Testing");
            bos.close();
        }
    }

El programa de demostración configura dos propiedades como parejas de clave-valor, y las almacena en fichero llamado test.prop. El fichero se parece a algo como esto:

    #Testing
    #Thu Nov 15 14:11:43 MST 2001
    key2=value2
    key1=value1

Entonces podremos ejecutar el siguiente programa para leer este fichero de propiedades en un objeto Properties, y acceder a las propiedadas:

    import java.io.*;
    import java.util.Properties;
    
    public class EnvDemo7 {
        public static void main(String args[]) 
                              throws IOException {
            FileInputStream fis =
                new FileInputStream("test.prop");
            BufferedInputStream bis =
                new BufferedInputStream(fis);
            Properties p = new Properties();
            p.load(bis);
            bis.close();
            System.out.println(
                  "key1=" + p.getProperty("key1"));
            System.out.println(
                  "key2=" + p.getProperty("key2"));
        }
    }

El resultado es:

    key1=value1
    key2=value2

Un punto final sobre la programación Java y el acceso al entorno tiene que ver con el método Runtime.exec. Este método se usa para llamar a un subprograma. El subprograma puede acceder a las variables de entorno. Algunas veces podríamos querer controlar las variables pasadas al subprograma. Aquí tenemos un ejemplo de cómo hacer esto:

    import java.io.*;
    
    public class EnvDemo8 {
        public static void main(String args[]) 
                                throws IOException {

            // invoke subprogram

            Runtime rt = Runtime.getRuntime();
            String env[] = null;
            //String env[] = new String[]{"test=456"};
            Process p = rt.exec("genv", env);

            // set up to read subprogram output
    
            InputStream is = p.getInputStream();
            InputStreamReader isr = 
                          new InputStreamReader(is);
            BufferedReader br = 
                          new BufferedReader(isr);
    
            // read output from subprogram 
            // and display it

            String s;
            while ((s = br.readLine()) != null) {
                System.out.println(s);
            }
    
            br.close();
        }
    }

Este programa invoca a un subprograma genv, que muestra el contenido de la variable de entorno test. genv es un programa C, escrito de esta forma:

    /* genv.c */
    
    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        printf("test=%s
", getenv("test"));
    }

Si el segundo argumento del método Runtime.exec es null, entonces el subprograma hereda el entorno del proceso llamante, es decir, el programa Java lanzador.

En el entorno Windows, seleccionamos la variable de entorno "test" diciento:

    set test=123

Luego ejecutamos el programa Java diciendo:

    java EnvDemo8

En entornos UNIX, decimos:

   env test=123 java EnvDemo8

El resultado es:

    test=123

Pero si comentamos la primera línea "env[] = " en EnvDemo8, y descomentamos la segunda línea, el resultado es:

    test=456

En el primer caso, el entorno se selecciona en la línea de comandos cuando se invocó el lanzador Java. Entonces es pasado al subprograma. Pero en el segundo caso, el entorno es sobreescrito dentro del programa EnvDemo8, y luego lo pasa al subprograma.

Para más información sobre el acceso al entorno desde aplicaciones Java puedes ver la Section 18.1.2, System Properties, and Section 18.2.2, Process Environments, en "The Java Programming Language Third Edition" de Arnold, Gosling, y Holmes.

Trabajar con Bases Numéricas

Hay muchas aplicaciones donde necesitamos manipular valores enteros usando bases o índices distintos de 10. Podríamos, por ejemplo, realizar manipulaciones lógicas usando valores binarios (base-2), o interpretando direcciones de memoria en hexadecimal (base-16). Toda la artimética de enteros en Java se hace usando operaciones binarias de complemento a 2. Sin embargo, podemos mostrar y convertir valores usando bases desde 2 hasta 36. En este truco veremos algunas facilidades que están disponibles para trabajar con bases numéricas.

Integer.parseInt se usa para convertir un string en un entero. Podemos especificar la base cuando llamamos a este método. Aquí tenemos un ejemplo sencillo del uso de este método:

    public class BaseDemo1 {
        public static void main(String args[]) {
            int ival = Integer.parseInt("10101", 2);
            System.out.println(
               "value of 10101 as 
                  decimal = " + ival);
        }
    }

Cuando ejecutamos el programa, el resultado es:

    value of 10101 as decimal = 21

El string binario 10101 se ha convertido en el valor decimal 21.

Podemos invertir el proceso con el método Integer.toString:

    public class BaseDemo2 {
        public static void main(String args[]) {
            int ival = 123456;
            String s = 
              Integer.toString(ival, 
                29).toUpperCase();
            System.out.println(
                        "123456 in base-29 = " + s);
        }
    }

El resultado aquí es:

    123456 in base-29 = 51N3

Esto dice que 51N3 en base-29 es lo mismo que 123456 en base-10. Cuanto más alta sea la base más compacta será la representación string del mismo número. Por ejemplo, un número en base 32 tiene sólo un 20% de dígitos que un número en base 2, simplemente porque cada digito en base 32 es equivalente a cinco dígitos de base 2.

Si estamos trabajando con una base mayor de 10, también se utilizarán los valores de las letras a-z como dígitos. Observa que se usan letras minúsculas. Si queremos un resultado en mayúsculas, necesitamos llamar al método toUpperCase.

La clase Integer también proporciona los métodos toBinaryString, toOctalString, y toHexString. Hay atajos que podemos usar en lugar del método toString. Para valores positivos, la operación es idéntica, pero para valores negativos, el valor del signo está codificado en el patrón de bits. Por ejemplo, Integer.toHexString(-1) resulta en:

    ffffffff

Este resultado es la representación hexadecimal en complemento a 2 de -1. En otras palabras, los valores negativos se tratan como cantidades sin signo.

Cuando usamos parseInt para convertir números, no se acepta un un prefijo como "0x" para hexadecimal. Lanzarán una excepción. Si queremos convertir strings que tengan estos tipos de prefijos, necesitamos usar Integer.decode, de esta forma:

    public class BaseDemo3 {
        public static void main(String args[]) {
            //int ival = Integer.parseInt(
            //                      "0x123456", 16);
            Integer in = Integer.decode("0x123456");
            int ival = in.intValue();
            System.out.println(
                        Integer.toString(ival, 16));
    
            in = Integer.decode("0123456");
            ival = in.intValue();
            System.out.println(
                         Integer.toString(ival, 8));
        }
    }

Cuando ejecutamos este programa, el resultado es:

    123456
    123456

La lista de prefijos aceptada por el método decode es:

    0x, 0X, #      hexadecimal
    0              octal

También podemos especificar bases distintas de 10 cuando usamos la clase BigInteger. Esta es una clase que soporta aritmética de precisión arbitraría. Aquí tenemos un ejemplo:

    import java.math.BigInteger;
    
    public class BaseDemo4 {
        public static void main(String args[]) {
            String num = 
                   "111111111111111111111111111111";
            BigInteger bi = new BigInteger(num, 2);
            BigInteger res = bi.multiply(bi);
    
            System.out.println("product in base-2 = ");
            System.out.println(res.toString(2));
            System.out.println();
    
            System.out.println(
                            "product in base-10 = ");
            System.out.println(res.toString(10));
            System.out.println();
    
            System.out.println(
                            "product 	 ");
            System.out.println(res.toString(16));
        }
    }

En este programa, un gran número binario es multiplicado por sí mismo, y luego el resultado es imprimido en base 2, base 10 y base 16. La salida del programa es:

    product in base-2 = 
    111111111111111111111111111110000000000000000000
    000000000001
    
    product in base-10 = 
    1152921502459363329
    
    product in base-16 = 
    fffffff80000001

Un último problema de trabajar con bases aparece en la conversión individual de dígitos desde o hacia un valor entero. Por ejemplo, si tenemos el dígito "e" en base-16, ¿cuál es el valor numérico de ese dítigo? O si tenemos el valor 29 en base-36, ¿cuál es el dígito correspondiente? Hay un par de métodos en la clase Character que podemos usar para realizar estas conversiones. Veamos un ejemplo:

    public class BaseDemo5 {
        public static void main(String args[]) {
            System.out.println(
                    "value of e in base-16 = " +
                          Character.digit('e', 16));
    
            System.out.println(
                      "digit for 29 in base-36 = " +
                         Character.forDigit(29, 36));
        }
    }

Cuando ejecutamos este programa, el resultado es:

    value of 'e' in base-16 = 14
    digit for 29 in base-36 = t

Entonces el número "e" en base-16 es equivalente al decimal 14, y el dígito "t" en base-36 tiene el valor 29.

Para más información sobre trabajar con bases numéricas, puedes ver la sección 11.1.5, The Integer Wrappers, en "The Java Programming Language Third Edition" de Arnold, Gosling, y Holmes.

Copyright y notas de la traducción

Nota respecto a la traducción

El original en inglés de la presente edición de los JDC Tech Tips fue escrita por Glen McCluskey, la traducción no oficial fue hecha por Juan A. Palos (Ozito), cualquier sugerencia o corrección hágala al correo [email protected] , sugerencia respecto a la edición original a mailto:[email protected]

Nota (Respecto a la edición via email)

Sun respeta su tiempo y su privacidad. La lista de correo de la Conexión del desarrollador Java se usa sólo para propósitos internos de Sun Microsystems(tm). Usted ha recibido este email porque se ha suscrito a la lista. Para desuscribirse vaya a la página de suscripciones, desmarque casilla apropiada y haga clic en el botón Update.

Suscripciones

Para suscribirse a la lista de correo de noticias de la JDC vaya a la página de suscripciones, elija los boletines a los que quiera suscribirse, y haga clic en Update.

Realimentación

¿Comentarios?, envie su sugerencias a los Consejos Técnicos de la JDC a mailto:[email protected]

Archivos

Usted encontrará las ediciones de los Consejos Técnicos de la JDC (en su original en inglés) en http://java.sun.com/jdc/TechTips/index.html

Copyright

Copyright 2001 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Este documento esta protegido por las leyes de autor. Para mayor información vea http://java.sun.com/jdc/copyright.html

Enlaces a sitios fuera de Sun

Los Consejos Técnicos de la JDC pueden dar enlaces a otros sitios y recursos. Ya que Sun no tiene control sobre esos sitios o recursos usted reconoce y acepta que Sun no es responsable por la disponibilidad de tales sitios o recursos, y no se responsabiliza por cualquier contenido, anuncios , productos u otros materiales disponibles en tales sitios o recursos. Sun no será responsable, directa o indirectamente, por cualquier daño o pérdida causada o supuestamente causada por o en relación con el uso de o seguridad sobre cualquier tal contenido, bienes o servicios disponibles en o através de cualquier sitio o recurso.

El original en Ingles de esta edición de los Consejos técnicos fue escrita por Glen McCluskey.

JDC Tech Tips December 04, 2001

Sun, Sun Microsystems, Java y Java Developer Connection (JDC) son marcas registradas de Sun Microsystems Incs. en los Estados Unidos y cualquier otro país.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP