– Amigo, tízkunyhó!

– Örülök, hogy megtanulhattam Jávát, kapitány!

"Nyugi, Amigo. Ma egy rendkívül érdekes témánk van. Beszélni fogunk arról, hogy egy Java program hogyan kölcsönhatásba lép a külső erőforrásokkal, és megvizsgálunk egy nagyon érdekes Java-állítást. Jobb, ha nem takarja be a fülét."

"Csupa fül vagyok."

"Miközben egy Java program fut, néha interakcióba lép a Java gépen kívüli entitásokkal. Például a lemezen lévő fájlokkal. Ezeket az entitásokat általában külső erőforrásoknak nevezik."

– Akkor mi számít belső erőforrásnak?

"A belső erőforrások a Java gépen belül létrehozott objektumok. Az interakció általában a következő sémát követi:

Próbálja ki az erőforrásokkal nyilatkozatot

"Az operációs rendszer szigorúan nyomon követi a rendelkezésre álló erőforrásokat , és szabályozza a különböző programok által hozzájuk való megosztott hozzáférést is. Ha például egy program módosít egy fájlt, akkor egy másik program nem tudja módosítani (vagy törölni) azt. Ez az elv nem fájlokra korlátozódik, de a legkönnyebben érthető példát nyújtják.

"Az operációs rendszernek vannak olyan funkciói (API-k), amelyek lehetővé teszik a program számára, hogy erőforrásokat szerezzen be és/vagy felszabadítson. Ha egy erőforrás foglalt, akkor csak az a program tud vele dolgozni, amelyik megszerezte. Ha egy erőforrás ingyenes, akkor bármelyik program beszerezheti azt.

"Képzeld el, hogy egy irodában közös kávésbögrék vannak. Ha valaki elvesz egy bögrét, akkor mások már nem tudják elvinni. De ha a bögrét elhasználták, kimosták és visszahelyezték a helyére, akkor bárki újra elviheti."

"Megvan. Ez olyan, mint a metrón vagy más tömegközlekedési eszközön lévő ülések. Ha egy hely szabad, akkor bárki elfoglalhatja. Ha egy hely foglalt, akkor azt az irányítja, aki elfoglalta."

"Így van. És most beszéljünk a külső erőforrások beszerzéséről . Minden alkalommal, amikor a Java program elkezd dolgozni egy fájllal a lemezen, a Java gép kizárólagos hozzáférést kér az operációs rendszertől. Ha az erőforrás ingyenes, akkor a Java gép beszerzi azt.

"De miután végzett a fájllal, ezt az erőforrást (fájlt) fel kell szabadítani, azaz értesítenie kell az operációs rendszert, hogy már nincs rá szüksége. Ha ezt nem teszi meg, akkor az erőforrás továbbra is amit a programod tart."

– Ez tisztességesen hangzik.

"Annak érdekében, hogy ez így is maradjon, az operációs rendszer vezet egy listát az egyes futó programok által elfoglalt erőforrásokról. Ha a program túllépi a hozzárendelt erőforráskorlátot, akkor az operációs rendszer többé nem ad új erőforrásokat.

"Olyan, mint a programok, amelyek az összes memóriát felemésztik..."

"Valami ilyesmi. A jó hír az, hogy ha a programod leáll, minden erőforrás automatikusan felszabadul (ezt maga az operációs rendszer teszi meg)."

– Ha ez a jó hír, akkor az azt jelenti, hogy rossz hírek is vannak?

"Pontosan így van. A rossz hír az, hogy ha szerveralkalmazást írsz..."

– De írjak ilyen pályázatokat?

"Sok szerveralkalmazást Java nyelven írnak, így nagy valószínűséggel munka miatt fogod írni őket. Ahogy mondtam, ha szerveralkalmazást írsz, akkor a szerverednek napokig, hetekhez, hónapokig megállás nélkül kell futnia, stb."

"Más szóval, a program nem áll le, és ez azt jelenti, hogy a memória nem szabadul fel automatikusan."

"Pontosan. És ha naponta 100 fájlt nyit meg, és nem zárja be őket, akkor néhány héten belül az alkalmazás eléri az erőforrás-korlátot és összeomlik."

"Ez messze elmarad a több hónapos stabil munkától! Mit lehet tenni?"

"A külső erőforrásokat használó osztályoknak speciális módszerük van a felszabadításukra: close().

"Íme egy példa egy olyan programra, amely ír valamit egy fájlba, majd bezárja a fájlt, amikor ez kész, azaz felszabadítja az operációs rendszer erőforrásait. Ez nagyjából így néz ki:

Kód jegyzet
String path = "c:\\projects\\log.txt";
FileOutputStream output = new FileOutputStream(path);
output.write(1);
output.close();
A fájl elérési útja.
Szerezze be a fájlobjektumot: szerezze be az erőforrást.
Írás a fájlba
Zárja be a fájlt - engedje fel az erőforrást

"Ah... Szóval, miután egy fájllal (vagy más külső erőforrással) dolgoztam, meg kell hívnom a close()metódust a külső erőforráshoz kapcsolt objektumon."

"Igen. Minden egyszerűnek tűnik. De kivételek előfordulhatnak a program futása közben, és a külső erőforrás nem szabadul fel."

– És ez nagyon rossz. Mit tegyek?

"Annak érdekében, hogy a metódus mindig meghívásra kerüljön, a kódunkat egy - - blokkba close()kell csomagolnunk, és hozzá kell adnunk a metódust a blokkhoz . Valahogy így fog kinézni:trycatchfinallyclose()finally

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

– Hmm... itt valami nincs rendben?

"Helyes. Ez a kód nem fordul le, mert a outputváltozó a blokkon belül van deklarálva try{}, ezért nem látható a blokkban finally.

Javítsuk ki:

FileOutputStream output = new FileOutputStream(path);

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

– Most már minden rendben?

"Rendben van, de nem fog működni, ha hiba történik az objektum létrehozásakor FileOutputStream, és ez könnyen megtörténhet.

Javítsuk ki:

FileOutputStream output = null;

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

– És most minden működik?

"Még mindig van néhány kritika. Először is, ha hiba történik az objektum létrehozásakor FileOutputStream, akkor a outputváltozó nulla lesz. Ezzel a lehetőséggel számolni kell a blokkban finally.

"Másodszor, a close()metódust mindig a blokkban hívják meg finally, ami azt jelenti, hogy a blokkban nem szükséges try. A végső kód így fog kinézni:

FileOutputStream output = null;

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

"Ha nem is vesszük figyelembe a catchblokkot, ami kihagyható, akkor a 3 kódsorunkból 10 lesz. De lényegében csak megnyitottuk a fájlt és 1-et írtunk."

"Phuu... Jó dolog, hogy lezárom a dolgot. Viszonylag érthető, de kissé unalmas, nem?"

"Így van. Ezért segítettek nekünk a Java alkotói azzal, hogy hozzáadtak némi szintaktikai cukrot. Most pedig térjünk át a program csúcspontjára, vagy inkább erre a leckére:

try-forrásokkal

"A 7. verziótól kezdve a Java új try-forrásokkal utasítással rendelkezik.

– Pontosan azért hozták létre, hogy megoldja a problémát a módszer kötelező meghívásával close().

– Ígéretesen hangzik!

"Az általános eset meglehetősen egyszerűnek tűnik:

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

"Szóval ez egy másik változata az try állításnak ?"

"Igen. A kulcsszó után zárójeleket kell hozzáadnia try, majd a zárójelben lévő külső erőforrásokkal objektumokat kell létrehoznia. A fordító minden egyes zárójelben lévő objektumhoz hozzáad egy finallyszakaszt és egy meghívást a close()metódushoz.

"Az alábbiakban két egyenértékű példa látható:

Hosszú kód Kód kipróbálható erőforrásokkal
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);
}

"Csodálatos! A -with-resources kódot használó kód trysokkal rövidebb és könnyebben olvasható. És minél kevesebb kódunk van, annál kisebb az esélye annak, hogy elgépelést vagy egyéb hibát követünk el."

"Örülök, hogy tetszik. Mellesleg hozzáadhatunk catchés finallyblokkokat a try-with-resources utasításhoz. Vagy nem adhatja hozzá őket, ha nincs rájuk szükség.

Több változó egyszerre

"Gyakran előfordulhat olyan helyzet, amikor több fájlt kell egyszerre megnyitnia. Tegyük fel, hogy egy fájlt másol, ezért két objektumra van szüksége: a fájlra, amelyből adatokat másol, és arra a fájlra, amelybe adatokat másol. .

"Ebben az esetben a try-with-resources utasítás lehetővé teszi, hogy egy, de több objektumot hozzon létre benne. Az objektumokat létrehozó kódot pontosvesszővel kell elválasztani. Íme az utasítás általános megjelenése:

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

Példa fájlok másolására:

Rövid kód Hosszú kód
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();
}

"Nos, mit is mondhatnánk itt? try- Az erőforrásokkal csodálatos dolog!"

– Azt mondhatjuk, hogy használnunk kell.