1. Eksterne ressurser

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. Interne ressurser er objektene som er opprettet inne i Java-maskinen.

Vanligvis følger interaksjonen denne ordningen:

Prøv-med-ressurser-erklæring

Sporingsressurser

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 (API) som lar et program anskaffe og/eller frigjøre ressurser. Hvis en ressurs er opptatt, kan bare programmet som har anskaffet den jobbe med den. Hvis en ressurs er gratis, kan ethvert program skaffe den.

Tenk deg at kontoret ditt har delte kaffekrus. Hvis noen tar et krus, kan ikke andre ta det lenger. Men når kruset er brukt, vasket og satt tilbake på plass, kan hvem som helst ta det igjen. Situasjonen med seter på buss eller T-bane er den samme. Hvis et sete er ledig, kan hvem som helst ta det. Hvis et sete er opptatt, kontrolleres det av personen som tok det.

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, kjøper Java-maskinen den.

Men etter at du er ferdig med å jobbe med filen, må denne ressursen (filen) frigis, dvs. du må varsle operativsystemet om at du ikke lenger trenger den. Hvis du ikke gjør dette, vil ressursen fortsatt holdes av programmet ditt.

Operativsystemet opprettholder 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.

Den gode nyheten er at hvis programmet avsluttes, frigjøres alle ressursene automatisk (operativsystemet selv gjør dette).

Den dårlige nyheten er at hvis du skriver en serverapplikasjon (og mange serverapplikasjoner er skrevet i Java), må serveren din kunne kjøre i dager, uker og måneder uten å stoppe. Og hvis du åpner 100 filer om dagen og ikke lukker dem, vil applikasjonen i løpet av et par uker nå ressursgrensen og krasje. Det er langt fra måneder med stabilt arbeid.


2. close()metode

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

Nedenfor gir vi 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

Etter å ha jobbet med en fil (eller andre eksterne ressurser), må du kalle close()metoden på objektet som er knyttet til den eksterne ressursen.

Unntak

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 dårlig.

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

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

Denne koden vil ikke kompilere, fordi outputvariabelen er 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();
}

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

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å redegjøres for i finallyblokken.

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 catchblokken, som kan utelates, så blir våre 3 linjer med kode 10. Men vi åpnet i grunnen bare filen og skrev 1. Litt tungvint, synes du ikke?


3. try-med-ressurser

Og her bestemte Javas skapere å strø litt syntaktisk sukker på oss. Fra og med sin 7. versjon har Java en ny try-with-resources-setning.

Den ble opprettet nettopp for å løse problemet med det obligatoriske kallet til metoden close(). Den generelle saken ser ganske enkel ut:

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

Dette er en annen variant av try uttalelsen . Du må legge til parenteser etter trynøkkelordet, og deretter opprette objekter med eksterne ressurser inne i parentesene. For hvert objekt i parentes 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);
}

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.

Forresten, vi kan legge til catchog finallyblokkere til try-with-resources-setningen. Eller du kan ikke legge dem til hvis de ikke er nødvendige.



4. Flere variabler samtidig

Forresten, 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 lar try-with-resources-setningen deg lage ett men flere objekter i den. Koden som lager objektene må skilles med semikolon. Her er det generelle utseendet til denne uttalelsen:

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

Eksempel på kopiering av filer:

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

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


5. AutoCloseablegrensesnitt

Men det er ikke alt. Den oppmerksomme leseren vil umiddelbart begynne å se etter fallgruver som begrenser hvordan dette utsagnet kan brukes.

Men hvordan tryfungerer -with-resources-setningen hvis klassen ikke har en close()metode? Vel, anta at ingenting vil bli kalt. Ingen metode, ikke noe problem.

Men hvordan tryfungerer -with-resources-setningen hvis klassen har flere close()metoder? Og de trenger argumenter for å bli sendt til dem? Og klassen har ikke en close()metode uten parametere?

Jeg håper du virkelig stilte deg selv disse spørsmålene, og kanskje flere andre.

For å unngå slike problemer kom Javas skapere med et spesielt grensesnitt kalt AutoCloseable, som bare har én metode - close(), som ikke har noen parametere.

De la også til begrensningen at bare objekter av klasser som implementererAutoCloseable kan deklareres som ressurser i en try-with-resources-setning. Som et resultat vil slike objekter alltid ha en close()metode uten parametere.

Tror du forresten det er mulig for en try-with-resources-setning å erklære som en ressurs et objekt hvis klasse har sin egen close()metode uten parametere, men som ikke implementerer AutoCloseable?

Den dårlige nyheten: Det riktige svaret er nei - klassene må implementere grensesnittet AutoCloseable.

Den gode nyheten: Java har mange klasser som implementerer dette grensesnittet, så det er svært sannsynlig at alt vil fungere som det skal.