"Amigo, tienhut!"

"Ik ben blij Java te leren, kapitein!"

"Rustig maar, Amigo. Vandaag hebben we een superinteressant onderwerp. We zullen het hebben over hoe een Java-programma omgaat met externe bronnen en we zullen een zeer interessante Java-verklaring bestuderen. Je kunt beter je oren niet bedekken."

"Ik luister."

"Terwijl een Java-programma wordt uitgevoerd, communiceert het soms met entiteiten buiten de Java-machine. Bijvoorbeeld met bestanden op schijf. Deze entiteiten worden meestal externe bronnen genoemd."

"Wat worden dan beschouwd als interne middelen?"

"Interne bronnen zijn de objecten die in de Java-machine zijn gemaakt. Meestal volgt de interactie dit schema:

Proberen-met-bronnen-verklaring

"Het besturingssysteem houdt nauwgezet de beschikbare bronnen bij en regelt ook de gedeelde toegang daartoe vanuit verschillende programma's. Als een programma bijvoorbeeld een bestand wijzigt, kan een ander programma dat bestand niet wijzigen (of verwijderen). Dit principe is niet beperkt tot bestanden, maar ze bieden het gemakkelijkst te begrijpen voorbeeld.

"Het besturingssysteem heeft functies (API's) waarmee een programma bronnen kan verwerven en/of vrijgeven. Als een bron bezet is, kan alleen het programma dat het heeft verkregen ermee werken. Als een bron vrij is, kan elk programma Het.

"Stel je voor dat een kantoor koffiemokken deelt. Als iemand een mok pakt, kunnen andere mensen hem niet meer pakken. Maar als de mok eenmaal is gebruikt, gewassen en teruggeplaatst, kan iedereen hem weer pakken."

"Begrepen. Het is net als stoelen in de metro of ander openbaar vervoer. Als een stoel vrij is, kan iedereen die nemen. Als een stoel bezet is, wordt deze gecontroleerd door de persoon die hem heeft ingenomen."

"Dat klopt. En laten we het nu hebben over het verkrijgen van externe bronnen . Elke keer dat uw Java-programma begint te werken met een bestand op schijf, vraagt ​​de Java-machine het besturingssysteem om exclusieve toegang daartoe. Als de bron vrij is, verwerft de Java-machine Het.

"Maar nadat u klaar bent met het werken met het bestand, moet deze bron (bestand) worden vrijgegeven, dat wil zeggen dat u het besturingssysteem moet melden dat u het niet langer nodig hebt. Doet u dit niet, dan blijft de bron gehouden door uw programma."

"Dat klinkt eerlijk."

"Om dat zo te houden, houdt het besturingssysteem een ​​lijst bij van bronnen die worden gebruikt door elk lopend programma. Als uw programma de toegewezen bronlimiet overschrijdt, zal het besturingssysteem u geen nieuwe bronnen meer geven.

"Het is net als programma's die al het geheugen kunnen opslokken..."

"Zoiets. Het goede nieuws is dat als je programma wordt beëindigd, alle bronnen automatisch worden vrijgegeven (het besturingssysteem doet dit zelf)."

"Als dat het goede nieuws is, betekent dat dan dat er slecht nieuws is?"

"Precies. Het slechte nieuws is dat als je een servertoepassing schrijft..."

"Maar schrijf ik zulke applicaties?"

"Veel serverapplicaties zijn in Java geschreven, dus hoogstwaarschijnlijk schrijf je ze voor je werk. Zoals ik al zei, als je een serverapplicatie schrijft, moet je server dagen, weken, maanden, enz."

"Met andere woorden, het programma wordt niet beëindigd en dat betekent dat het geheugen niet automatisch wordt vrijgegeven."

"Precies. En als je 100 bestanden per dag opent en ze niet sluit, dan bereikt je applicatie binnen een paar weken de limiet van de bronnen en crasht."

'Dat is veel minder dan maandenlang stabiel werk! Wat kan er gedaan worden?'

"Klassen die externe bronnen gebruiken, hebben een speciale methode om ze vrij te geven: close().

"Hier is een voorbeeld van een programma dat iets naar een bestand schrijft en het bestand vervolgens sluit als het klaar is, dwz het maakt de bronnen van het besturingssysteem vrij. Het ziet er ongeveer zo uit:

Code Opmerking
String path = "c:\\projects\\log.txt";
FileOutputStream output = new FileOutputStream(path);
output.write(1);
output.close();
Het pad naar het bestand.
Haal het bestandsobject op: verkrijg de bron.
Schrijf naar het bestand
Sluit het bestand - geef de bron vrij

"Ah... Dus, nadat ik met een bestand (of andere externe bronnen) heb gewerkt, moet ik de close()methode aanroepen op het object dat aan de externe bron is gekoppeld."

"Ja. Het lijkt allemaal eenvoudig. Maar tijdens de uitvoering van een programma kunnen er uitzonderingen optreden en wordt de externe bron niet vrijgegeven."

"En dat is heel erg. Wat te doen?"

"Om ervoor te zorgen dat de close()methode altijd wordt aangeroepen, moeten we onze code in een try- catch- finallyblok wikkelen en de close()methode aan het finallyblok toevoegen. Het ziet er ongeveer zo uit:

try
{
   FileOutputStream output = new FileOutputStream(path);
   output.write(1);
   output.close();
}
catch (IOException e)
{
   e.printStackTrace();
}
finally
{
   output.close();
}

"Hm... Is hier iets mis?"

"Juist. Deze code wordt niet gecompileerd, omdat de outputvariabele binnen het blok wordt gedeclareerd try{}en daarom niet zichtbaar is in het finallyblok.

Laten we het oplossen:

FileOutputStream output = new FileOutputStream(path);

try
{
   output.write(1);
   output.close();
}
catch (IOException e)
{
   e.printStackTrace();
}
finally
{
   output.close();
}

"Is alles nu goed?"

"Het is oké, maar het werkt niet als er een fout optreedt wanneer we het FileOutputStreamobject maken, en dit kan vrij gemakkelijk gebeuren.

Laten we het oplossen:

FileOutputStream output = null;

try
{
   output = new FileOutputStream(path);
   output.write(1);
   output.close();
}
catch (IOException e)
{
   e.printStackTrace();
}
finally
{
   output.close();
}

"En werkt alles nu?"

"Er zijn nog een paar punten van kritiek. Ten eerste, als er een fout optreedt bij het maken van het FileOutputStreamobject, dan outputis de variabele null. Met deze mogelijkheid moet rekening worden gehouden in het finallyblok.

"Ten tweede wordt de close()methode altijd aangeroepen in het finallyblok, wat betekent dat het niet nodig is in het tryblok. De uiteindelijke code ziet er als volgt uit:

FileOutputStream output = null;

try
{
   output = new FileOutputStream(path);
   output.write(1);
}
catch (IOException e)
{
   e.printStackTrace();
}
finally
{
   if (output!=null)
      output.close();
}

"Zelfs als we geen rekening houden met het catchblok, dat kan worden weggelaten, worden onze 3 regels code 10. Maar we hebben in feite gewoon het bestand geopend en 1 geschreven."

"Pff... Het is maar goed dat de zaak is afgerond. Betrekkelijk begrijpelijk, maar een beetje vervelend, nietwaar?"

"Zo is het. Daarom hebben de makers van Java ons geholpen door wat syntactische suiker toe te voegen. Laten we nu verder gaan met het hoogtepunt van het programma, of beter gezegd, deze les:

try-met-middelen

"Vanaf de 7e versie heeft Java een nieuwe try-with-resources-instructie.

"Het is precies gemaakt om het probleem op te lossen met de verplichte aanroep van de close()methode."

"Het klinkt veelbelovend!"

"Het algemene geval ziet er vrij eenvoudig uit:

try (ClassName name = new ClassName())
{
   Code that works with the name variable
}

"Dus dit is een andere variant van de try verklaring ?"

"Ja. U moet haakjes toevoegen achter het trytrefwoord en vervolgens objecten maken met externe bronnen tussen haakjes. Voor elk object tussen haakjes voegt de compiler een finallysectie en een aanroep toe aan de close()methode.

"Hieronder staan ​​twee gelijkwaardige voorbeelden:

Lange code Codeer met try-with-resources
FileOutputStream output = null;

try
{
   output = new FileOutputStream(path);
   output.write(1);
}
finally
{
   if (output!=null)
   output.close();
}
try(FileOutputStream output = new FileOutputStream(path))
{
   output.write(1);
}

"Cool! De code die try-with-resources gebruikt, is veel korter en gemakkelijker te lezen. En hoe minder code we hebben, hoe kleiner de kans op een typefout of een andere fout."

"Ik ben blij dat je het leuk vindt. Trouwens, we kunnen toevoegen catchen finallyblokken toevoegen aan de try-with-resources-verklaring. Of je kunt ze niet toevoegen als ze niet nodig zijn.

Meerdere variabelen tegelijk

"Vaak kom je een situatie tegen waarin je meerdere bestanden tegelijk moet openen. Laten we zeggen dat je een bestand kopieert, dus je hebt twee objecten nodig: het bestand waaruit je gegevens kopieert en het bestand waarnaar je gegevens kopieert .

"In dit geval trykunt u met de instructie -with-resources er één maar meerdere objecten in maken. De code die de objecten maakt, moet worden gescheiden door puntkomma's. Dit is de algemene weergave van deze instructie:

try (ClassName name = new ClassName(); ClassName2 name2 = new ClassName2())
{
   Code that works with the name and name2 variables
}

Voorbeeld van het kopiëren van bestanden:

Korte code Lange code
String src = "c:\\projects\\log.txt";
String dest = "c:\\projects\\copy.txt";

try(FileInputStream input = new FileInputStream(src);

FileOutputStream output = new FileOutputStream(dest))
{
   byte[] buffer = input.readAllBytes();
   output.write(buffer);
}
String src = "c:\\projects\\log.txt";
String dest = "c:\\projects\\copy.txt";

FileInputStream input = null;
FileOutputStream output = null;

try
{
   input = new FileInputStream(src);
   output = new FileOutputStream(dest);

   byte[] buffer = input.readAllBytes();
   output.write(buffer);
}
finally
{
   if (input!=null)
      input.close();
   if (output!=null)
      output.close();
}

"Nou, wat kunnen we hier zeggen? try-met-middelen is geweldig!"

"Wat we kunnen zeggen is dat we het moeten gebruiken."