Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Este capítulo cubre una variedad de temas que ampliarán su conocimiento del Java 2 SDK. Abarca:
Cuando un programa basado en la tecnología Java se ejecuta desde una ventana de comandos, se
le pueden pasar cero o más argumentos desde la línea de comandos. Ellos son cadenas de
caracteres: una única cadena, como, por ejemplo, arg1, o cadenas de caracteres entre comillas,
como, por ejemplo, "otro argumento".
Este programa despliega cada argumento pasado al programa TestArgs desde la línea de
comandos. Por ejemplo, la ejecución del programa anterior con los siguientes argumentos produce
la salida que se detalla:
Las propiedades del sistema son otro mecanismo para indicar parámetros en un programa en
tiempo de ejecución. Una propiedad es una correspondencia entre un nombre de propiedad y un
valor. Ambos elementos son cadenas de caracteres. La clase Properties representa esta clase de
correspondencias. El método System.getProperties devuelve el objeto de las propiedades del
sistema. El método System.getProperty(String) devuelve el valor, como cadena de caracteres,
de la propiedad cuyo nombre es el explicitado en el parámetro String. El método
System.getProperty(String, String) ofrece un valor por defecto (el segundo parámetro), el cual
es devuelto en caso de que el nombre de la propiedad pasada como primer argumento no exista en
el sistema.
Hay también miembros estáticos en las clases de envoltura que realizan conversiones de los valores
de las propiedades: Boolean.getBoolean(String), Integer.getInteger(String) y
Long.getLong(String). El argumento de tipo String es el nombre de la propiedad. Si la propiedad
no existe, entonces devolverá false o null (respectivamente).
Un objeto de la clase Properties contiene una correspondencia entre los nombres de la propiedad
(String) y sus valores (String). Tiene dos métodos principales para devolver la propiedad de un
valor: getProperty(String) y getProperty(String, String). Este último ofrece la posibilidad de
especificar un valor por defecto, el cual será devuelto si el nombre de la propiedad pasado como
parámetro no existe.
La Línea 6 obtiene el conjunto de propiedades del sistema y la Línea 7 recupera una enumeración
de todos los nombres de las propiedades en el conjunto de propiedades.
Se utiliza un objeto Enumeration para iterar sobre los elementos en una colección. Este es muy
similar a un Iterator, el cual se describe en "Iteradores", apartado 9.10
El método hasMoreElements devuelve el valor true si hay más elementos sobre los cuales iterar y
el método nextElement devuelve el siguiente elemento en la enumeración.
La Línea 11 devuelve el valor de la propiedad y las líneas 12-13 despliegan el nombre y el valor de
la propiedad.
Fig 1
1 import java.util.Properties;
2 import java.util.Enumeration;
3
4 public class TestProperties {
5 public static void main(String[] args) {
6 Properties props = System.getProperties();
7 Enumeration propNames = props.propertyNames();
8
9 while ( propNames.hasMoreElements() ) {
10 String propName = (String)
propNames.nextElement();
11 String property = props.getProperty(propName);
12 System.out.println("property '" + propName
13 + "' is '" + property + "'");
14 }
15 }
Fig 2
La mayoría de las aplicaciones deben interaccionar con el usuario. Algunas veces, esta interacción
se lleva a cabo a través de la entrada de un texto y de la salida en la consola (usando el teclado
como entrada estándar y la ventana de comandos como la salida estándar).
Java 2 SDK soporta una consola de Entrada/Salida (E/S) con tres variables públicas, en la clase
java.lang.System:
void println(boolean)
void println(char)
void println(double)
void println(float)
void println(int)
void println(long)
void println(char[])
void println(Object)
Existe un conjunto de métodos sobrecargados, denominados print, que no agregan el
carácter de nueva línea
El ejemplo en la Figura muestra una técnica que se debería usar para leer información en un
objeto String desde la consola de entrada estándar
La Línea 5 declara una variable String de nombre s, que el programa usa para mantener cada línea
leída de la entrada estándar. La Líneas 8-10 asocian el System.in con dos objetos de soporte que
manejan el flujo de bytes provenientes de la entrada estándar. El objeto ir de la calse
InputStreamReader lee caracteres y los convierte en bytes en
caracteres Unicode. El objeto in asociado a la clase BufferedReader provee el método readLine, el
cual permite al programa leer desde la entrada estándar de una línea a la vez.
La Línea 15 lee la primera línea del texto desde la entrada estándar. La iteración while (Líneas 16-
19) despliega en forma iterativa la línea actual y lee la línea siguiente. Este código puede ser
reescrito de forma más concisa (pero más críptica) como (ver Figura )
Dado que el método readLine puede lanzar una excepción de E/S, se debe incluir todo el código en
un bloque try-catch. (ver Figura )
La Línea 23 cierra el flujo de entrada más lejano para liberar cualquier recurso del sistema
relacionado con crear ese flujo de objetos. (ver Figura )
Fig 1
1 import java.io.*;
2
3 public class KeyboardInput {
4 public static void main (String[] args) {
5 String s;
6 // Create a buffered reader to read
7 // each line from the keyboard.
8 InputStreamReader ir
9 = new InputStreamReader(System.in);
10 BufferedReader in = new BufferedReader(ir);
11
12 System.out.println("Unix: Type ctrl-d to exit." +
13 "\nWindows: Type ctrl-z to exit");
Fig 2
14 try {
15 // Read each input line and echo it
16 s = in.readLine();
17 while ( s != null ) {
18 System.out.println("Read: " + s);
19 s = in.readLine();
20 }
Fig 4
21
22 // Close the buffered reader.
23 in.close();
Fig 5
El lenguaje de programación Java versión 1.5 provee la funcionalidad de printf, al estilo del
lenguaje C. Este ofrece salida formateada estándar desde el programa, la que permite a los
programadores migrar código heredado. Se puede usar el método printf siguiendo la sintaxis normal
de C y C++. Esta funcionalidad de formateo está también disponible en la
clase String en el método format. Se puede usar el método printf como sigue:
System.out.printf("name count\n");
String s = String.format("%s %5d%n", user, total);
Se puede usar %n para los caracteres de nueva línea, en lugar del \n, para la
independencia de plataforma.
La clase Scanner ofrece la funcionalidad de entrada formateada, que es parte del paquete
java.util. Dicho paquete ofrece métodos para obtener valores primitivos y para realizar bloqueos
mientras espera por una entrada desde el usuario. Un ejemplo se muestra en el Código de la Figura
.
En el Código dela Figura , la Línea 5 crea una referencia a Scanner pasándole directamente la
entrada de la consola. La línea 6 recupera el valor de la cadena de caracteres desde la entrada
dada usando el método next de Scanner. La línea 8 obtiene el valor entero de la entrada dada
usando el método nextInt. La línea 10 cierra la entrada para el usuario.
1 import java.io.*;
2 import java.util.Scanner;
3 public class ScanTest {
4 public static void main(String [] args) {
5 Scanner s = new Scanner(System.in);
6 String param = s.next();
7 System.out.println("the param 1" + param);
8 int value = s.nextInt();
9 System.out.println("second param" + value);
10 s.close();
11 }
12 }
La E/S es uno de los más importantes elementos de programación. La tecnología Java incluye un
rico conjunto de flujos de E/S. En la sección previa se mostró cómo usar los flujos para comunicarse
con el usuario a través de la salida estándar (usualmente una ventana de comandos) y la entrada
estándar (usualmente el teclado). Esta sección examina varias
técnicas simples para leer y escribir archivos con foco en los datos de los caracteres, incluyendo:
La clase File provee varias utilidades para manejar archivos y obtener información de ellos. En la
tecnología Java, un directorio es otro archivo. Puede crear un objeto File que representa un
directorio y luego usarlo para identificar otros archivos, como se muestra en la tercera viñeta.
File myFile;
myFile = new File("myfile.txt");
myFile = new File("MyDocs", "myfile.txt");
File myDir = new File("MyDocs");
myFile = new File(myDir, "myfile.txt");
El constructor que se usa, frecuentemente depende del objeto archivo al que se quiera acceder.
Por ejemplo, si se usa sólo un archivo en la aplicación, se utiliza el primer constructor. Sin embargo,
si se utilizan varios archivos de un directorio común, se sugiere usar el segundo o el tercer
constructor, ya que debería ser más fácil.
Después de haber creado un objeto File, se puede usar cualquier método en la siguiente sección
para recoger información acerca del archivo.
El Nombre de Archivo
Los siguientes métodos retornan nombres de archivos:
String getName()
String getPath()
String getAbsolutePath()
String getParent()
boolean renameTo(File newName)
boolean mkdir()
String[] list()
long lastModified()
long length()
boolean delete()
La Verificación de Archivos
Los siguientes métodos devuelven información acerca de los atributos del archivo:
boolean exists()
boolean canWrite()
boolean canRead()
boolean isFile()
boolean isDirectory()
boolean isAbsolute()
El código en la Figura lee un archivo de texto y reproduce cada línea a la salida estándar, la cual
despliega el archivo.
La Línea 5 crea un nuevo objeto File basado en el primer argumento pasado desde la línea de
comando. Las Líneas 10 y 11 crean un buffered reader que contiene un lector de
archivos. Este código lanza una FileNotFoundException, si el archivo no existe.
El Código de la Figura lee un archivo de texto y reproduce cada línea a la salida estándar. De
esta manera, se despliega el archivo. En éste Código, la iteración while en las Líneas 15-19 realiza
exactamente lo mismo que el programa KeyboardInput. Este lee cada línea de texto en el
buffered reader y lo reproduce en la salida estándar.La Línea 21 cierra el buffered reader, que, a
su vez, cierra el lector de archivo asociado al buffer del archivo.El código de manejo de excepción
entre las Líneas 23-25 atrapa la excepción FileNotFoundException que puede ser lanzada por el
constructor FileReader. Las Líneas 27-30 manejan cualquier otra excepción basada en I/O que
pueda ser lanzada (por los métodos readLine y close).
El Código de la Figura lee líneas de la entrada desde el teclado y envía cada una de ellas a un
archivo.
Al igual que el Código de la Figura , la Línea 6 del Código de la Figura crea un objeto File,
basado en el primer argumento de la línea de comandos. Las Líneas 10-11 crean un flujo de lectura
de caracteres desde el flujo binario (System.in). Las Líneas 12-13 crean un buffered reader para la
entrada estándar. Las Líneas 15-16 crean un print writer asociado a un file writer para el archivo
creado en la Línea 6.
Las Líneas 19-20 (ver Figura ) indican al usuario que debe ingresar las líneas de texto que serán
grabadas en el archivo y que presione Control-d para finalizar dicho ingreso. Las Líneas 23-25 leen
del flujo de entrada y graban en el archivo, de una línea por vez.
Las Líneas 28 y 29 cierran los flujos de entrada y salida. Las Líneas 31-33 manejan las excepciones
de I/O que deben ser lanzadas. (ver Figura )
Fig 1
1 import java.io.*;
2 public class ReadFile {
3 public static void main (String [] args) {
4 // Crea el archivo
5 File file = new File(args[0]);
6
7 try {
8 // Crea un buffered reader
9 // para leer cada línea del archivo.
10 BufferedReader in
11 = new BufferedReader(new FileReader(file));
12 String s;
13
Fig 2
Fig 3
1 import java.io.*;
2
3 public class WriteFile {
4 public static void main (String[] args) {
5 // Crear Archivo
6 File file = new File(args[0]);
7
8 try {
9 // Crea un buffered reader
10 InputStreamReader isr
11 = new InputStreamReader(System.in);
12 BufferedReader in
13 = new BufferedReader(isr);
14 // Crea un escritor de la impresora en este archivo.
15 PrintWriter out
16 = new PrintWriter(new FileWriter(file));
17 String s;
Fig 4
18
19 System.out.print("Enter file text. ");
20 System.out.println("[Type ctrl-d to stop.]");
21
22 // Lee cada línea de ingreso
23 while ((s = in.readLine()) != null) {
24 out.println(s);
25 }
26
Fig 5
Una colección es un objeto simple que representa un grupo de objetos, llamados elementos.
Típicamente, las colecciones tratan con muchos objetos, todos de un tipo en particular (esto es,
todos descienden del mismo tipo padre)
Las colecciones mantienen referencias a objetos del tipo Object. Esto permite que cualquier objeto
pueda guardarse en una colección. También necesita el uso de una correcta conversión de tipos
antes de usar el objeto y luego de recuperarlo de la colección.
La Figura muestra un diagrama UML primario con las interfaces yl las clases de implementación
de la API de colecciones.La clase HashSet da una implementación de la interfaz Set. Las clases
ArrayList y LinkedList suministran una implementación de la interfaz List .
En el ejemplo de la Figura , el programa declara una variable (set) del tipo Set y la inicializa con
un nuevo objeto HashSet. Luego, le agrega algunos elementos y envía el conjunto a la salida
estándar. El intento de agregar los ítems duplicados en las líneas 11 y 12 falla; de esa manera, el
método add devuelve el valor false.
1. import java.util.*;
2.
3. public class SetExample {
4. public static void main(String[] args) {
5. Set set = new HashSet();
6. set.add("one");
7. set.add("second");
8. set.add("3rd");
9. set.add(new Integer(4));
10. set.add(new Float(5.0F));
11. set.add("second"); // duplicado, no se agrega
12. set.add(new Integer(4)); // duplicado, no se agrega
13. System.out.println(set);
14. }
15. }
16.10.2 Un Ejemplo de List
En el siguiente ejemplo, el programa declara una variable (list) del tipo List y es inicializada a un
nuevo objeto ArrayList. Este, luego agrega unos pocos elementos y despliega la lista en la salida
estándar. Dado que las listas le permiten duplicados, las Líneas 11 y 12 son exitosas.
1 import java.util.*;
2
3 public class ListExample {
4 public static void main(String[] args) {
5 List list = new ArrayList();
6 list.add("one");
7 list.add("second");
8 list.add("3rd");
9 list.add(new Integer(4));
10 list.add(new Float(5.0F));
11 list.add("second"); // // duplicado, se agrega
12 list.add(new Integer(4)); // // duplicado, se
agrega
13 System.out.println(list);
14 }
15 }
La API de Colecciones es una característica mejorada de la Java 2 SDK, aunque existían unas
pocas clases de colecciones en la JDK versión 1.0 y JDK versión 1.1. Estas clases todavía existen
en el SDK con la misma interfaz, pero han sido actualizadas para interaccionar con la nueva API de
colecciones.
La clase Vector implementa la interfaz List. La clase Stack es una extensión de Vector que agrega
las típicas operaciones de stack: push, pop y peek. HashTable es una implementación de Map. La
clase Properties (vista en "Propiedades del Sistema" en el apartado 9.4) es una extensión de
HashTable que sólo usa String para las claves y los valores.
Cada una de estas colecciones tiene un método elements que devuelve un objeto Enumeration. La
interfaz Enumeration es una interfaz similar a la interfaz Iterator, pero incompatible con ella. Por
ejemplo, hasNext es reemplazado por hasMoreElements en la interfaz Enumeration .
Las clases de Collection usan el tipo Object para permitir diferentes entradas y tipos de retorno.
Usted necesita convertirlos explícitamente para obtener el objeto que necesita. Esto no es seguro.
La solución para este problema es hacer uso de la funcionalidad genérica. Esta provee información
para el compilador acerca del tipo de colección usada. Por lo tanto, la verificación de tipos está
resuelta automáticamente en tiempo de ejecución. Esto elimina la conversión explícita de los tipos
de datos a ser usados en la colección. Con la adición del autoboxing a los tipos primitivos, se
pueden usar genéricos y escribir un código más simple y comprensible.
En el segmento de código previo se necesita una clase de envoltura Integer para convertir los tipos
(typecasting) mientras traen el valor entero de la lista. En tiempo de ejecución, el programa
necesita verificar el tipo para la lista. El ArrayList debería haberse declarado como
ArrayList<Integer>, de manera que el compilador esté informado sobre el tipo de la colección a
ser usada. Mientras que, al recuperar el valor, no hay necesidad de una clase de envoltura Integer.
Cuando usa el nuevo compilador de J2SE versión 5 con código que ya tenía escrito o no genérico,
usted debe ver una advertencia (warning) especial. Una clase de ejemplo que envía esta
advertencia es la ilustrada en el Código de la Figura
javac GenericsWarning.java
Estas son solo advertencias. La clase compila bien y esas advertencias pueden ser ignoradas. Sin
embargo, puede usarlas para recordarle de modificar su código para que este sea un código
generic-friendly. Para resolver esta advertencia, necesitará cambiar la Línea 4:List<Integer>
list = new ArrayList<Integer>();
1 import java.util.*;
2 public class GenericsWarning {
3 public static void main(String[] args) {
4 List list = new ArrayList();
5 list.add(0, new Integer(42));
6 int total = ((Integer)list.get(0)).intValue();
7 }
8 }
Usted puede explorar una colección usando un iterador. La interfaz básica Iterator le permite
explorar hacia adelante una colección. En el caso de una iteración sobre un conjunto, el orden no es
determinante.. El orden de una iteración sobre una lista que se mueve hacia adelante a través de los
elementos. Un objeto List también soporta un ListIterator, el cual permite recorrer la lista hacia
atrás.
La Figura muestra un diagrama UML de la interfaz genérica Iterator para la API de Colecciones.
El método remove permite al código borrar el ítem actual en la iteración (el ítem devuelto por el
método next o previous más reciente). Si el método remove no es soportado por la colección
subyacente, entonces se produce una excepción de tipo Unsupported OperationException.
Mientras se usa una ListIterator, es común moverse a través de la lista sólo en una dirección: o
hacia delante usando next o hacia atrás usando previous. Si usa el previous inmediatamente
después del next, entonces recibirá el mismo elemento; así como si se llama a next después de
previous.
El método set cambia el elemento de la colección que está siendo referenciado por el cursor del
iterador. El método add inserta el nuevo elemento dentro de la colección inmediatamente antes del
cursor del iterador. Por lo tanto, si llama a previous después de add, entonces devolverá el elemento
recién agregado. Sin embargo, una llamada a next no se verá afectada. Si la colección subyacente
no soporta el método set o el método add, entonces lanzará una excepción del tipo Unsupported
OperationException.
Una iteración for mejorada supera estas fallas asignando directamente el objeto Collection a la
variable iterator en la iteración for. Se puede usar al recorrer los elementos de un arreglo además
de eliminar la necesidad del elemento índice mientras recorre los elementos de un arreglo. El uso de
las iteraciones for mejoradas comparada con los iteradores se ilustra a continuación:
En el segmento de código previo, el método deleteAll usa la variable i tres veces en el bucle for y
produce la opción de error cuando se usa la variable por segunda vez. También, la iteración for usa
el método hasNext de Iterator para obtener el próximo elemento a ser procesado. Será difícil para
usted recordar todos estos métodos. La iteración for mejorada elimina el uso de métodos de
iteración separados y minimiza el número de ocurrencias de la variable de iteración. El método
deleteAll con la iteración for mejorada se ilustra a continuación:
La iteración for mejorada en arreglos le permite recorrer a través de los elementos del arreglo sin
usar una variable índice para él. Esto se ilustra en el siguiente segmento de código.
Con la funcionalidad de la iteración for mejorada, el recorrido de los for anidados se hace simple y
fácil de comprender reduciendo la ambigüedad de las variables que están siendo usadas en las
iteraciones for anidadas.
List<Subject> subjects=...;
List<Teacher> teachers=...;
List<Course> courseList = ArrayList<Course)();
for ( Subject subj : subjects ) {
for ( Teacher tchr : teachers ) {
courseList.add(new Course(subj, tchr));
}
}