Slutföringsmetoden, stängbart gränssnitt och försök med resurser (Java 7) - 1

"Hej, Amigo!"

"Jag bestämde mig för att diskutera slutföringsmetoden () med dig."

"Om du kommer ihåg, är finalize() en speciell metod som anropas av ett objekt innan sopsamlaren förstör det."

"Denna metods huvudsakliga syfte är att frigöra använda externa icke-Java-resurser genom att stänga filer, I/O-strömmar och så vidare."

"Tyvärr lever den här metoden inte upp till våra förväntningar. Den virtuella Java-maskinen kan skjuta upp att förstöra ett objekt, samt anropa finalize-metoden, så länge den vill. Dessutom garanterar den inte att den här metoden kommer att vara anropas överhuvudtaget. Det finns massor av situationer där det inte blir anropat, allt i namnet "optimering"."

"Jag har två referenser till dig:"

Joshua Bloch har skrivit en bra artikel om den här metoden: länk
Jag ska parafrasera ett kort utdrag:

  1. finalize() kan endast användas i två fall:
    1. För att verifiera eller rensa resurser med loggning.
    2. När man arbetar med inbyggd kod som inte är avgörande för resursläckor.
  2. finalize() gör GC 430 gånger långsammare vid rengöring av objekt
  3. finalize() kanske inte anropas
Om jag i en intervju säger att finalisera är en skadlig och farlig krycka vars själva existens är förvirrande, skulle jag ha rätt?

"Tja, det gjorde min dag, Ellie."

"Java 7 har ett nytt uttalande för att ersätta finalize- metoden. Det kallas prova-med-resurser. Det är egentligen inte en ersättning för finalize , snarare är det ett alternativt tillvägagångssätt."

"Är det som try-catch, men med resurser?"

"Det är nästan som try-catch . Saken är, till skillnad från finalize ()-metoden, finally- blocket i en try- catch-finally- sats exekveras alltid. Programmerare har också använt denna teknik när de har behövt frigöra resurser, stäng trådar osv.

"Här är ett exempel:"

InputStream is = null;
try
{
 is = new FileInputStream("c:/file.txt");
 is.read(…);
}
finally
{
 if (is != null)
 is.close();
}

"Oavsett om försöksblocket kördes korrekt eller om det fanns ett undantag, kommer finalblocket alltid att anropas och det är möjligt att frigöra upptagna resurser där."

"Så, i Java 7 togs beslutet att göra detta tillvägagångssätt officiellt, som så:"

try(InputStream is = new FileInputStream("c:/file.txt"))
{
 is.read(…);
}

"Denna speciella try- sats kallas try-with-resources (liknande hur samlingar har ett alternativ för called foreach )."

"Lägg märke till att det efter försöket finns parenteser där variabler deklareras och objekt skapas. Dessa objekt kan användas inom försöksblocket som anges med hakparenteserna. När försöksblocket är klart exekveras det, oavsett om det slutade normalt eller där var ett undantag, kommer metoden close() att anropas på alla objekt som skapas inom parentes."

"Vad intressant! Den här notationen är mycket mer kompakt än den föregående. Jag är inte säker på att jag förstår den än."

"Det är inte så svårt som du tror."

"Så, kan jag ange klassen för varje objekt inom parentes?"

— Ja, visst, annars skulle parentesen vara till liten nytta.

"Och om jag behöver anropa en annan metod efter att ha avslutat försöksblocket, var ska jag lägga det?"

"Det är lite mer subtilt här. Java 7 introducerar följande gränssnitt:"

public interface AutoCloseable
{
 void close() throws Exception;
}

"Din klass kan implementera det här gränssnittet. Och sedan kan du använda dess objekt i en try-with-resources-sats. Endast sådana objekt kan skapas inom parentesen av en try-with-resources-sats för «automatisk stängning»."

"Med andra ord, jag måste åsidosätta stängningsmetoden och skriva kod i den för att «städa upp» mitt objekt, och jag kan inte ange en annan metod?"

"Japp. Men du kan ange flera objekt - separera dem bara med ett semikolon:"

try(
InputStream is = new FileInputStream("c:/file.txt");
OutputStream os = new FileOutputStream("c:/output.txt")
)
{
 is.read(…);
 os.write(…);
}

"Det är bättre, men inte så coolt som jag hade hoppats."

"Det är inte så illa. Du vänjer dig. Med tiden."