1. Eksterne ressourcer

Når et Java-program kører, interagerer det nogle gange med enheder uden for Java-maskinen. For eksempel med filer på disk. Disse enheder kaldes normalt eksterne ressourcer. Interne ressourcer er de objekter, der er oprettet inde i Java-maskinen.

Typisk følger interaktionen dette skema:

Prøv-med-ressourcer-erklæring

Sporing af ressourcer

Operativsystemet holder nøje styr på de tilgængelige ressourcer og styrer også delt adgang til dem fra forskellige programmer. For eksempel, hvis et program ændrer en fil, så kan et andet program ikke ændre (eller slette) den fil. Dette princip er ikke begrænset til filer, men de giver det lettest forståelige eksempel.

Operativsystemet har funktioner (API'er), der gør det muligt for et program at erhverve og/eller frigive ressourcer. Hvis en ressource er optaget, kan kun det program, der har erhvervet den, arbejde med den. Hvis en ressource er gratis, kan ethvert program erhverve den.

Forestil dig, at dit kontor har fælles kaffekrus. Hvis nogen tager et krus, så kan andre mennesker ikke længere tage det. Men når først kruset er brugt, vasket og sat tilbage på plads, så kan enhver tage det igen. Situationen med sæder på en bus eller metro er den samme. Hvis en plads er ledig, så kan enhver tage den. Hvis et sæde er optaget, så kontrolleres det af den person, der tog det.

Anskaffelse af eksterne ressourcer .

Hver gang dit Java-program begynder at arbejde med en fil på disken, beder Java-maskinen styresystemet om eksklusiv adgang til den. Hvis ressourcen er fri, anskaffer Java-maskinen den.

Men når du er færdig med at arbejde med filen, skal denne ressource (fil) frigives, dvs. du skal give styresystemet besked om, at du ikke længere har brug for den. Hvis du ikke gør dette, vil ressourcen fortsat blive holdt af dit program.

Operativsystemet vedligeholder en liste over ressourcer optaget af hvert kørende program. Hvis dit program overskrider den tildelte ressourcegrænse, vil operativsystemet ikke længere give dig nye ressourcer.

Den gode nyhed er, at hvis dit program afsluttes, frigives alle ressourcer automatisk (operativsystemet selv gør dette).

Den dårlige nyhed er, at hvis du skriver en serverapplikation (og mange serverapplikationer er skrevet i Java), skal din server kunne køre i dage, uger og måneder uden at stoppe. Og hvis du åbner 100 filer om dagen og ikke lukker dem, vil din applikation om et par uger nå sin ressourcegrænse og gå ned. Det er langt fra måneders stabilt arbejde.


2. close()metode

Klasser, der bruger eksterne ressourcer, har en særlig metode til at frigive dem: close().

Nedenfor giver vi et eksempel på et program, der skriver noget til en fil og derefter lukker filen, når den er færdig, dvs. det frigør operativsystemets ressourcer. Det ser sådan ud:

Kode Bemærk
String path = "c:\\projects\\log.txt";
FileOutputStream output = new FileOutputStream(path);
output.write(1);
output.close();
Stien til filen.
Hent filobjektet: Hent ressourcen.
Skriv til filen
Luk filen - slip ressourcen

Efter at have arbejdet med en fil (eller andre eksterne ressourcer), skal du kalde close()metoden på det objekt, der er knyttet til den eksterne ressource.

Undtagelser

Det hele virker simpelt. Men undtagelser kan forekomme, mens et program kører, og den eksterne ressource vil ikke blive frigivet. Og det er meget slemt.

For at sikre, at close()metoden altid kaldes, skal vi pakke vores kode ind i en try- catch- finallyblok og tilføje close()metoden til finallyblokken. Det kommer til at se sådan ud:

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

Denne kode vil ikke kompilere, fordi outputvariablen er erklæret inde i try {}blokken og derfor ikke er synlig i finallyblokken.

Lad os ordne det:

FileOutputStream output = new FileOutputStream(path);

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

Det er okay, men det vil ikke fungere, hvis der opstår en fejl, når vi opretter objektet FileOutputStream, og det kan ske ret nemt.

Lad os ordne det:

FileOutputStream output = null;

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

Der er stadig et par kritikpunkter. For det første, hvis der opstår en fejl under oprettelse af FileOutputStreamobjektet, outputvil variablen være null. Denne mulighed skal der redegøres for i finallyblokken.

For det andet close()kaldes metoden altid i finallyblokken, hvilket betyder, at den ikke er nødvendig i tryblokken. Den endelige kode vil se sådan ud:

FileOutputStream output = null;

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

Selvom vi ikke overvejer blokken catch, som kan udelades, så bliver vores 3 linjer kode 10. Men vi åbnede i princippet bare filen og skrev 1. Lidt besværligt, synes du ikke?


3. try-med-ressourcer

Og her besluttede Javas skabere at drysse noget syntaktisk sukker på os. Startende med sin 7. version har Java en ny try-med-ressourcer-erklæring.

Den blev skabt netop for at løse problemet med det obligatoriske kald til metoden close(). Det generelle tilfælde ser ret simpelt ud:

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

Dette er en anden variation af try udsagnet . Du skal tilføje parenteser efter trynøgleordet og derefter oprette objekter med eksterne ressourcer inde i parentesen. For hvert objekt i parentes tilføjer compileren en finallysektion og et kald til close()metoden.

Nedenfor er to tilsvarende eksempler:

Lang kode Kode med prøv-med-ressourcer
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, der bruger try-med-ressourcer, er meget kortere og lettere at læse. Og jo mindre kode vi har, jo mindre chance for at lave en tastefejl eller anden fejl.

Forresten kan vi tilføje catchog finallyblokere til try-with-resources-sætningen. Eller du kan ikke tilføje dem, hvis de ikke er nødvendige.



4. Flere variable på samme tid

I øvrigt kan du ofte støde på en situation, hvor du skal åbne flere filer på samme tid. Lad os sige, at du kopierer en fil, så du har brug for to objekter: filen, som du kopierer data fra, og filen, som du kopierer data til.

I dette tilfælde trylader -with-resources-sætningen dig oprette et men flere objekter i det. Koden, der opretter objekterne, skal adskilles af semikolon. Her er det generelle udseende af denne erklæring:

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

Eksempel på kopiering af 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);
}

Nå, hvad kan vi sige her? try-med-ressourcer er en vidunderlig ting!


5. AutoCloseablegrænseflade

Men det er ikke alt. Den opmærksomme læser vil straks begynde at lede efter faldgruber, der begrænser, hvordan dette udsagn kan anvendes.

Men hvordan tryfungerer -with-ressources-sætningen, hvis klassen ikke har en close()metode? Tja, antag, at intet vil blive kaldt. Ingen metode, intet problem.

Men hvordan tryfungerer -with-resources-sætningen, hvis klassen har flere close()metoder? Og de har brug for argumenter for at blive videregivet til dem? Og klassen har ikke en close()metode uden parametre?

Jeg håber du virkelig stillede dig selv disse spørgsmål, og måske endnu andre.

For at undgå sådanne problemer kom Javas skabere med en speciel grænseflade kaldet AutoCloseable, som kun har én metode - close(), som ikke har nogen parametre.

De tilføjede også den begrænsning, at kun objekter af klasser, der implementerer,AutoCloseable kan erklæres som ressourcer i en try-with-resources-sætning. Som et resultat vil sådanne objekter altid have en close()metode uden parametre.

Tror du i øvrigt, at det er muligt for en try-with-resources-sætning at erklære som en ressource et objekt, hvis klasse har sin egen close()metode uden parametre, men som ikke implementerer AutoCloseable?

Den dårlige nyhed: Det rigtige svar er nej - klasserne skal implementere grænsefladen AutoCloseable.

Den gode nyhed: Java har mange klasser, der implementerer denne grænseflade, så det er meget sandsynligt, at alt vil fungere, som det skal.