"¡Amigo, diez chozas!"
"¡Estoy feliz de aprender Java, Capitán!"
"Tranquilo, Amigo. Hoy tenemos un tema súper interesante. Hablaremos sobre cómo un programa Java interactúa con recursos externos y estudiaremos una declaración de Java muy interesante. Mejor no te tapes los oídos".
"Soy todo oídos."
"Cuando se ejecuta un programa Java, a veces interactúa con entidades fuera de la máquina Java. Por ejemplo, con archivos en el disco. Estas entidades generalmente se denominan recursos externos".
"Entonces, ¿qué se consideran recursos internos?"
"Los recursos internos son los objetos creados dentro de la máquina Java. Normalmente, la interacción sigue este esquema:
"El sistema operativo realiza un seguimiento riguroso de los recursos disponibles y también controla el acceso compartido a ellos desde diferentes programas. Por ejemplo, si un programa cambia un archivo, otro programa no puede cambiar (o eliminar) ese archivo. Este principio no es limitado a archivos, pero proporcionan el ejemplo más fácilmente comprensible.
"El sistema operativo tiene funciones (API) que permiten que un programa adquiera y/o libere recursos. Si un recurso está ocupado, solo el programa que lo adquirió puede trabajar con él. Si un recurso está libre, cualquier programa puede adquirirlo". él.
"Imagínese que una oficina ha compartido tazas de café. Si alguien toma una taza, entonces otras personas ya no pueden tomarla. Pero una vez que la taza se usa, se lava y se vuelve a colocar en su lugar, cualquiera puede tomarla de nuevo".
"Entendido. Es como los asientos en el metro u otro transporte público. Si un asiento está libre, cualquiera puede tomarlo. Si un asiento está ocupado, entonces lo controla la persona que lo tomó".
"Así es. Y ahora hablemos de adquirir recursos externos . Cada vez que su programa Java comienza a trabajar con un archivo en el disco, la máquina Java le pide al sistema operativo acceso exclusivo a él. Si el recurso es gratuito, entonces la máquina Java adquiere él.
"Pero una vez que haya terminado de trabajar con el archivo, este recurso (archivo) debe liberarse, es decir, debe notificar al sistema operativo que ya no lo necesita. Si no lo hace, el recurso seguirá siendo sostenido por su programa".
"Suena justo."
"Para mantenerlo así, el sistema operativo mantiene una lista de recursos ocupados por cada programa en ejecución. Si su programa excede el límite de recursos asignado, entonces el sistema operativo ya no le dará nuevos recursos.
"Es como programas que pueden consumir toda la memoria..."
"Algo así. La buena noticia es que si su programa finaliza, todos los recursos se liberan automáticamente (el propio sistema operativo lo hace)".
"Si esas son las buenas noticias, ¿significa que hay malas noticias?"
"Precisamente. La mala noticia es que si estás escribiendo una aplicación de servidor..."
"¿Pero escribo tales aplicaciones?"
"Muchas aplicaciones de servidor están escritas en Java, por lo que lo más probable es que las escriba para el trabajo. Como decía, si está escribiendo una aplicación de servidor, entonces su servidor necesita ejecutarse sin parar durante días, semanas, meses, etc."
"En otras palabras, el programa no termina, y eso significa que la memoria no se libera automáticamente".
"Exactamente. Y si abre 100 archivos al día y no los cierra, en un par de semanas su aplicación alcanzará su límite de recursos y fallará".
"¡Eso está muy lejos de meses de trabajo estable! ¿Qué se puede hacer?"
"Las clases que usan recursos externos tienen un método especial para liberarlos: close()
.
"Aquí hay un ejemplo de un programa que escribe algo en un archivo y luego cierra el archivo cuando termina, es decir, libera los recursos del sistema operativo. Se ve más o menos así:
Código | Nota |
---|---|
|
La ruta al archivo. Obtener el objeto de archivo: adquirir el recurso. Escribir en el archivo Cerrar el archivo - liberar el recurso |
"Ah... Entonces, después de trabajar con un archivo (u otros recursos externos), tengo que llamar al close()
método en el objeto vinculado al recurso externo".
"Sí. Todo parece simple. Pero pueden ocurrir excepciones a medida que se ejecuta un programa, y el recurso externo no se liberará".
"Y eso es muy malo. ¿Qué hacer?"
"Para asegurarnos de que close()
siempre se llame al método, debemos envolver nuestro código en un bloque try
- catch
- finally
y agregar el close()
método al finally
bloque. Se verá así:
try
{
FileOutputStream output = new FileOutputStream(path);
output.write(1);
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
output.close();
}
"Hmm... ¿Algo anda mal aquí?"
"Correcto. Este código no se compilará, porque la output
variable se declara dentro del try{}
bloque y, por lo tanto, no es visible en el finally
bloque.
Arreglemoslo:
FileOutputStream output = new FileOutputStream(path);
try
{
output.write(1);
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
output.close();
}
"¿Está todo bien ahora?"
"Está bien, pero no funcionará si ocurre un error cuando creamos el FileOutputStream
objeto, y esto podría suceder con bastante facilidad.
Arreglemoslo:
FileOutputStream output = null;
try
{
output = new FileOutputStream(path);
output.write(1);
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
output.close();
}
"¿Y todo funciona ahora?"
"Todavía hay algunas críticas. Primero, si ocurre un error al crear el FileOutputStream
objeto, entonces la output
variable será nula. Esta posibilidad debe tenerse en cuenta en el finally
bloque.
"Segundo, el close()
método siempre se llama en el finally
bloque, lo que significa que no es necesario en el try
bloque. El código final se verá así:
FileOutputStream output = null;
try
{
output = new FileOutputStream(path);
output.write(1);
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if (output!=null)
output.close();
}
"Incluso si no consideramos el catch
bloque, que se puede omitir, nuestras 3 líneas de código se convierten en 10. Pero básicamente abrimos el archivo y escribimos 1".
"Uf... Es algo bueno que concluye el asunto. Relativamente comprensible, pero algo tedioso, ¿no?"
"Así es. Es por eso que los creadores de Java nos ayudaron agregando un poco de azúcar sintáctico. Ahora pasemos a lo más destacado del programa, o más bien, a esta lección:
try
-con-recursos
"A partir de su séptima versión, Java tiene una nueva try
declaración -con-recursos.
"Se creó precisamente para solucionar el problema de la llamada obligatoria al close()
método".
"¡Suena prometedor!"
"El caso general parece bastante simple:
try (ClassName name = new ClassName())
{
Code that works with the name variable
}
"¿Así que esta es otra variación de la try
declaración ?"
"Sí. Debe agregar paréntesis después de la try
palabra clave y luego crear objetos con recursos externos dentro de los paréntesis. Para cada objeto entre paréntesis, el compilador agrega una finally
sección y una llamada al close()
método.
"A continuación se muestran dos ejemplos equivalentes:
código largo | Codifique con probar con recursos |
---|---|
|
|
"¡Genial! El código que usa try
-with-resources es mucho más corto y más fácil de leer. Y cuanto menos código tengamos, menos posibilidades de cometer un error tipográfico u otro error".
"Me alegro de que te guste. Por cierto, podemos agregar catch
y finally
bloques a la try
declaración -con-recursos. O no puedes agregarlos si no son necesarios.
Varias variables al mismo tiempo
"A menudo puede encontrarse con una situación en la que necesita abrir varios archivos al mismo tiempo. Digamos que está copiando un archivo, por lo que necesita dos objetos: el archivo del que está copiando datos y el archivo al que está copiando datos .
"En este caso, la try
declaración -with-resources le permite crear uno pero varios objetos en ella. El código que crea los objetos debe estar separado por punto y coma. Aquí está la apariencia general de esta declaración:
try (ClassName name = new ClassName(); ClassName2 name2 = new ClassName2())
{
Code that works with the name and name2 variables
}
Ejemplo de copia de archivos:
Código corto | código largo |
---|---|
|
|
"Bueno, ¿qué podemos decir aquí? ¡ try
Con-recursos es algo maravilloso!"
"Lo que podemos decir es que debemos usarlo".