"Amigo, ti-hytte!"

"Jeg er glad for at lære Java, kaptajn!"

"Rolig, Amigo. I dag har vi et superinteressant emne. Vi vil tale om, hvordan et Java-program interagerer med eksterne ressourcer, og vi vil studere en meget interessant Java-erklæring. Det er bedre ikke at holde for ørerne."

"Jeg lytter."

"Når et Java-program kører, interagerer det nogle gange med entiteter uden for Java-maskinen. For eksempel med filer på disken. Disse entiteter kaldes normalt eksterne ressourcer."

"Hvad betragtes så som interne 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

" Operativsystemet holder nøje styr på de tilgængelige ressourcer , og kontrollerer også delt adgang til dem fra forskellige programmer. For eksempel, hvis et program ændrer en fil, 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, er det kun det program, der har erhvervet den, der kan arbejde med den. Hvis en ressource er gratis, så kan ethvert program anskaffe sig det.

"Forestil dig, at et 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."

"Forstår det. Det er ligesom sæder i metroen eller anden offentlig transport. Hvis et sæde er gratis, så kan alle tage det. Hvis et sæde er optaget, så er det kontrolleret af den person, der tog det."

"Det er rigtigt. Og lad os nu tale om at anskaffe 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 ledig, så henter Java-maskinen det.

"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, så vil ressourcen blive ved med at være holdt af dit program."

"Det lyder rimeligt."

"For at holde det sådan, vedligeholder operativsystemet en liste over ressourcer optaget af hvert kørende program. Hvis dit program overskrider den tildelte ressourcegrænse, så vil operativsystemet ikke længere give dig nye ressourcer.

"Det er ligesom programmer, der kan æde al hukommelsen op..."

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

"Hvis det er den gode nyhed, betyder det så, at der er dårlige nyheder?"

"Nøjagtigt. Den dårlige nyhed er, at hvis du skriver en serverapplikation..."

"Men skriver jeg sådanne ansøgninger?"

"Mange serverapplikationer er skrevet i Java, så højst sandsynligt vil du skrive dem til arbejde. Som jeg sagde, hvis du skriver en serverapplikation, så skal din server køre non-stop i dage, uger, måneder, etc."

"Med andre ord, programmet afsluttes ikke, og det betyder, at hukommelsen ikke automatisk frigives."

"Nøjagtigt. Og hvis du åbner 100 filer om dagen og ikke lukker dem, så vil din applikation om et par uger nå sin ressourcegrænse og gå ned."

"Det er langt fra måneders stabilt arbejde! Hvad kan gøres?"

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

"Her er et eksempel på et program, der skriver noget til en fil og så lukker filen, når den er færdig, dvs. det frigør styresystemets ressourcer. Det ser nogenlunde 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

"Ah... Så efter at have arbejdet med en fil (eller andre eksterne ressourcer), er jeg nødt til at kalde metoden close()på det objekt, der er knyttet til den eksterne ressource."

"Ja. 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. Hvad skal man gøre?"

"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 vil se nogenlunde sådan ud:

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

"Hmm... Er der noget galt her?"

"Right. Denne kode vil ikke kompilere, fordi variablen outputer 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();
}

"Er alt i orden nu?"

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

"Og fungerer alt nu?"

"Der er stadig et par kritikpunkter. For det første, hvis der opstår en fejl ved oprettelse af objektet FileOutputStream, så outputvil variablen være nul. Denne mulighed skal tages højde 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åledes 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 bund og grund bare filen og skrev 1."

"Puh... Det er en god ting, der afslutter sagen. Relativt forståeligt, men noget træls, ikke?"

"Så det er. Det er derfor, Javas skabere hjalp os ved at tilføje noget syntaktisk sukker. Lad os nu gå videre til programmets højdepunkt, eller rettere, denne lektion:

try-med-ressourcer

"Startende med sin 7. version har Java en ny try-med-ressourcer-erklæring.

"Den blev skabt netop for at løse problemet med den obligatoriske opfordring til metoden close()."

"Det lyder lovende!"

"Den generelle sag ser ret simpel ud:

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

"Så dette er en anden variation af try udsagnet ?"

"Ja. Du skal tilføje parenteser efter nøgleordet try, og derefter oprette objekter med eksterne ressourcer inde i parentesen. For hvert objekt i parentesen 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);
}

"Fedt! Koden, der bruger try-med-ressourcer, er meget kortere og lettere at læse. Og jo mindre kode vi har, jo mindre er chancen for at lave en tastefejl eller anden fejl."

"Jeg er glad for, at du kan lide det. I øvrigt kan vi tilføje catchog finallyblokere til try-med-ressourcer-erklæringen. Eller du kan ikke tilføje dem, hvis de ikke er nødvendige.

Flere variabler på samme tid

"Du kan 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: den fil, du kopierer data fra, og den fil, du kopierer data til. .

"I dette tilfælde trylader -with-resources-sætningen dig oprette ét men flere objekter i den. Koden, der skaber objekterne, skal adskilles af semikolon. Her er det generelle udseende af denne sætning:

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

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

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

"Det, vi kan sige, er, at vi skal bruge det."