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:
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 |
---|---|
|
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
- finally
blok og tilføje close()
metoden til finally
blokken. 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 output
variablen er erklæret inde i try {}
blokken og derfor ikke er synlig i finally
blokken.
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 FileOutputStream
objektet, output
vil variablen være null. Denne mulighed skal der redegøres for i finally
blokken.
For det andet close()
kaldes metoden altid i finally
blokken, hvilket betyder, at den ikke er nødvendig i try
blokken. 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 try
nøgleordet og derefter oprette objekter med eksterne ressourcer inde i parentesen. For hvert objekt i parentes tilføjer compileren en finally
sektion og et kald til close()
metoden.
Nedenfor er to tilsvarende eksempler:
Lang kode | Kode med prøv-med-ressourcer |
---|---|
|
|
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 catch
og finally
blokere 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 try
lader -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 |
---|---|
|
|
Nå, hvad kan vi sige her? try
-med-ressourcer er en vidunderlig ting!
5. AutoCloseable
græ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 try
fungerer -with-ressources-sætningen, hvis klassen ikke har en close()
metode? Tja, antag, at intet vil blive kaldt. Ingen metode, intet problem.
Men hvordan try
fungerer -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.
GO TO FULL VERSION