"Amigo, ti-hytte!"

"Jeg er glad for å lære Java, kaptein!"

"Rolig, Amigo. I dag har vi et superinteressant emne. Vi skal snakke om hvordan et Java-program samhandler med eksterne ressurser, og vi skal studere en veldig interessant Java-uttalelse. Det er best å ikke dekke for ørene."

"Jeg lytter."

"Når et Java-program kjører, samhandler det noen ganger med enheter utenfor Java-maskinen. For eksempel med filer på disk. Disse enhetene kalles vanligvis eksterne ressurser."

"Hva regnes da som interne ressurser?"

"Interne ressurser er objektene som er opprettet inne i Java-maskinen. Vanligvis følger interaksjonen dette skjemaet:

Prøv-med-ressurser-erklæring

"Operativsystemet holder nøye oversikt over ressursene som er tilgjengelige , og kontrollerer også delt tilgang til dem fra forskjellige programmer. For eksempel, hvis ett program endrer en fil, kan ikke et annet program endre (eller slette) den filen. Dette prinsippet er ikke begrenset til filer, men de gir det lettest forståelige eksemplet.

"Operativsystemet har funksjoner (APIer) som lar et program skaffe og/eller frigjøre ressurser. Hvis en ressurs er opptatt, kan bare programmet som skaffet den jobbe med den. Hvis en ressurs er ledig, kan et hvilket som helst program skaffe seg den.

"Tenk deg at et kontor har delte kaffekrus. Hvis noen tar et krus, så kan ikke andre ta det lenger. Men når kruset først er brukt, vasket og satt tilbake på plass, så kan hvem som helst ta det igjen."

"Skjønner det. Det er som seter på T-banen eller annen offentlig transport. Hvis et sete er ledig, så kan hvem som helst ta det. Hvis et sete er opptatt, så kontrolleres det av personen som tok det."

"Det stemmer. Og la oss nå snakke om å anskaffe eksterne ressurser . Hver gang Java-programmet ditt begynner å jobbe med en fil på disken, ber Java-maskinen operativsystemet om eksklusiv tilgang til den. Hvis ressursen er ledig, henter Java-maskinen den.

"Men etter at du er ferdig med å jobbe med filen, må denne ressursen (filen) frigis, dvs. du må gi beskjed til operativsystemet om at du ikke lenger trenger den. Hvis du ikke gjør dette, vil ressursen fortsette å være holdt av programmet ditt."

"Det høres rettferdig ut."

"For å holde det slik, opprettholder operativsystemet en liste over ressurser som er okkupert av hvert kjørende program. Hvis programmet ditt overskrider den tildelte ressursgrensen, vil operativsystemet ikke lenger gi deg nye ressurser.

"Det er som programmer som kan spise opp alt minnet..."

"Noe sånt. Den gode nyheten er at hvis programmet ditt avsluttes, frigjøres alle ressurser automatisk (operativsystemet selv gjør dette)."

"Hvis det er de gode nyhetene, betyr det at det er dårlige nyheter?"

"Nettopp det. Den dårlige nyheten er at hvis du skriver en serverapplikasjon..."

— Men skriver jeg slike søknader?

"Mange serverapplikasjoner er skrevet i Java, så mest sannsynlig vil du skrive dem for jobb. Som jeg sa, hvis du skriver en serverapplikasjon, må serveren din kjøre non-stop i dager, uker, måneder, etc."

"Med andre ord, programmet avsluttes ikke, og det betyr at minnet ikke frigjøres automatisk."

"Akkurat. Og hvis du åpner 100 filer om dagen og ikke lukker dem, vil applikasjonen din nå ressursgrensen i løpet av et par uker og krasjer."

"Det er langt fra måneder med stabilt arbeid! Hva kan gjøres?"

"Klasser som bruker eksterne ressurser har en spesiell metode for å frigjøre dem: close().

"Her er et eksempel på et program som skriver noe til en fil og så lukker filen når den er ferdig, dvs. at det frigjør operativsystemets ressurser. Det ser omtrent slik ut:

Kode Merk
String path = "c:\\projects\\log.txt";
FileOutputStream output = new FileOutputStream(path);
output.write(1);
output.close();
Banen til filen.
Hent filobjektet: hent ressursen.
Skriv til filen
Lukk filen - slipp ressursen

"Ah... Så, etter å ha jobbet med en fil (eller andre eksterne ressurser), må jeg kalle metoden close()på objektet som er knyttet til den eksterne ressursen."

"Ja. Det hele virker enkelt. Men unntak kan forekomme når et program kjører, og den eksterne ressursen vil ikke bli frigitt."

"Og det er veldig ille. Hva skal jeg gjøre?"

"For å sikre at close()metoden alltid kalles, må vi pakke inn koden vår i en try- catch- finallyblokk og legge til close()metoden i finallyblokken. Den vil se omtrent slik ut:

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

"Hmm... Er det noe galt her?"

"Riktig. Denne koden vil ikke kompilere, fordi variabelen outputer deklarert inne i try{}blokken, og derfor ikke er synlig i blokken finally.

La oss fikse det:

FileOutputStream output = new FileOutputStream(path);

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

"Er alt i orden nå?"

"Det er greit, men det vil ikke fungere hvis det oppstår en feil når vi oppretter objektet FileOutputStream, og dette kan skje ganske enkelt.

La oss fikse det:

FileOutputStream output = null;

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

"Og fungerer alt nå?"

"Det er fortsatt noen kritikk. For det første, hvis det oppstår en feil når du oppretter objektet FileOutputStream, outputvil variabelen være null. Denne muligheten må tas med i blokken finally.

"For det andre close()kalles metoden alltid i finallyblokken, noe som betyr at den ikke er nødvendig i tryblokken. Den endelige koden vil se slik ut:

FileOutputStream output = null;

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

"Selv om vi ikke vurderer blokken catch, som kan utelates, så blir våre 3 linjer med kode 10. Men vi åpnet i utgangspunktet bare filen og skrev 1."

"Puff ... det er en god ting som avslutter saken. Relativt forståelig, men litt kjedelig, ikke sant?"

"Så det er. Derfor hjalp Javas skapere oss ved å tilsette litt syntaktisk sukker. La oss nå gå videre til høydepunktet i programmet, eller rettere sagt, denne leksjonen:

try-med-ressurser

"Fra og med sin 7. versjon har Java en ny try-with-resources-erklæring.

"Den ble opprettet nettopp for å løse problemet med det obligatoriske kallet til metoden close()."

"Det høres lovende ut!"

"Den generelle saken ser ganske enkel ut:

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

"Så dette er en annen variant av utsagnet try ? "

"Ja. Du må legge til parenteser etter nøkkelordet try, og deretter lage objekter med eksterne ressurser inne i parentesen. For hvert objekt i parentesen legger kompilatoren til en finallyseksjon og et kall til close()metoden.

"Nedenfor er to tilsvarende eksempler:

Lang kode Kode med prøv-med-ressurser
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);
}

"Kult! Koden som bruker try-med-ressurser er mye kortere og lettere å lese. Og jo mindre kode vi har, jo mindre sjanse for å gjøre en skrivefeil eller annen feil."

"Jeg er glad du liker det. Forresten, vi kan legge til catchog finallyblokkere i try-med-ressurser-erklæringen. Eller du kan ikke legge dem til hvis de ikke er nødvendige.

Flere variabler samtidig

"Du kan ofte støte på en situasjon når du trenger å åpne flere filer samtidig. La oss si at du kopierer en fil, så du trenger to objekter: filen du kopierer data fra og filen du kopierer data til .

"I dette tilfellet trylar -with-resources-setningen deg lage ett men flere objekter i den. Koden som oppretter objektene må skilles med semikolon. Her er det generelle utseendet til denne setningen:

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

Eksempel på kopiering av filer:

Kort kode Lang kode
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();
}

"Vel, hva kan vi si her? try-med-ressurser er en fantastisk ting!"

"Det vi kan si er at vi bør bruke det."