Închiderea fluxurilor de intrare Java InputStreams (Programare, Java, Inputstream)

Jason Watkins a intrebat.

Am câteva întrebări cu privire la utilizarea metodei close() atunci când se utilizează Java InputStreams. Din ceea ce văd și citesc de la majoritatea dezvoltatorilor, ar trebui să apelați întotdeauna în mod explicit close() pentru un InputStream atunci când nu mai este necesar. Dar, astăzi, m-am interesat de utilizarea unui fișier de proprietăți Java și fiecare exemplu pe care l-am găsit are ceva de genul acesta:

Properties props = new Properties();
try {
    props.load(new FileInputStream("message.properties"));
    //omitted.
} catch (Exception ex) {}

Cu exemplul de mai sus, nu există nicio modalitate de a apela explicit close() deoarece InputStream este inaccesibil după ce a fost utilizat. Am văzut multe utilizări similare ale InputStream-urilor, chiar dacă pare să contrazică ceea ce majoritatea oamenilor spun despre închiderea explicită. Am citit în JavaDocs de la Oracle și nu se menționează dacă metoda Properties.load() închide InputStream. Mă întreb dacă acest lucru este în general acceptabil sau dacă este de preferat să se procedeze mai degrabă în felul următor:

Properties props = new Properties();
InputStream fis = new FileInputStream("message.properties");
try {
    props.load(fis);
    //omitted.
} catch (Exception ex) {
    //omitted.
} finally {
    try {
        fis.close();
    } catch (IOException ioex) {
        //omitted.
    }
}

Care dintre aceste metode este mai bună și/sau mai eficientă? Sau contează cu adevărat?

Comentarii

  • Mulțumesc tuturor pentru răspunsurile pe care le-ați oferit. Mi-aș dori să le pot accepta pe toate ca fiind răspunsul. Acest lucru are acum sens pentru mine. –  > Por Jason Watkins.
8 răspunsuri
Bill Șopârla

Exemplele din Tutorial de proprietăți închid FileInputStream în mod explicit după încărcare, deci cred că este sigur să presupunem că load metoda nu este responsabilă pentru aceasta, ci tu ești responsabil.

// create and load default properties
Properties defaultProps = new Properties();
FileInputStream in = new FileInputStream("defaultProperties");
defaultProps.load(in);
in.close();

Doar ca referință, am verificat Apache Harmony a metodei Properties, , și aceasta face nu închide fluxul la încărcare.

Comentarii

  • tutorialul Properties este explicația pe care o așteptam. Mulțumesc pentru link! –  > Por Jason Watkins.
Jon

Clasa Properties înfășoară fluxul de intrare într-un LineReader pentru a citi fișierul de proprietăți. Din moment ce tu furnizezi fluxul de intrare, este responsabilitatea ta să îl închizi.

Al doilea exemplu este de departe o modalitate mai bună de a gestiona fluxul, nu vă bazați pe altcineva să îl închidă pentru dumneavoastră.

O îmbunătățire pe care ați putea-o face este să utilizați IOUtils.closeQuietly()

pentru a închide fluxul, de exemplu:

Properties props = new Properties();
InputStream fis = new FileInputStream("message.properties");
try {
    props.load(fis);
    //omitted.
} catch (Exception ex) {
    //omitted.
} finally {
    IOUtils.closeQuietly(fis);
}

Comentarii

  • DON’T USE, depreciat și eliminat fără înlocuire în IOUtils 2.6. „Vă rugăm să utilizați instrucțiunea try-with-resources sau să gestionați manual excepțiile suprimate.” –  > Por Sergio.
Daniel Voina

Eu aș opta pentru try-with-resources (cel puțin pentru Java 7+):

Properties props = new Properties();

try(InputStream fis = new FileInputStream("message.properties")) {
    props.load(fis);
    //omitted.
} catch (Exception ex) {
    //omitted.
}

close() ar trebui să fie apelat automat atunci când blocul try este părăsit.

kwo2002

Dacă folosiți Java 7+ puteți folosi acest lucru:

try(InputStream is = new FileInputStream("message.properties")) {
    // ...
}

Adrian Smith

În documentație nu se menționează că props.load ar închide fluxul de intrare. Ar trebui să închideți manual fluxul de intrare într-un bloc finally, așa cum sugerați.

Nu este normal ca o funcție să închidă un fișier InputStream. Aceeași convenție se aplică ca și în cazul memoriei în limbajele care nu au colecție de gunoaie: Dacă este posibil, cel care deschide fluxul ar trebui să închidă fluxul. Altfel, este foarte ușor să lași un flux deschis (crezi că o funcție îl va închide, dar nu o face, sau ceva de genul…).

Comentarii

  • +1 la „cel care deschide fluxul ar trebui să închidă fluxul” Dacă acest lucru nu este posibil, comentariul metodei ar trebui să îl instruiască pe apelant să facă acest lucru. Primul exemplu de cod este o practică proastă. –  > Por leonbloy.
  • Cea mai recentă versiune patch a Java 1.6 are acest comentariu pentru props.load(Reader): Fluxul specificat rămâne deschis după ce această metodă se întoarce. Înainte de a găsi acest Q&A, am citit în TL;DR’d documentele pentru props.load(Reader) și nu puteam înțelege de ce fluxul meu era încă deschis! –  > Por kevinarpe.
Nathan Hughes

Se pare că primul exemplu de cod ajunge să se bazeze pe metoda finalize din FileInputStream pentru a închide efectiv fișierul. Aș spune că al doilea exemplu este mai bun, chiar dacă în ambele cazuri fișierul este închis.

Există cazuri, cum ar fi fluxurile de octeți, în care închiderea nu face nimic și poate fi omisă, altfel cred că este mai bine să închizi în mod explicit fișierul într-un bloc finally. Dacă îl deschideți, îl închideți.

Există o carte pe site-ul Oracle numită Performanța platformei Java care discută despre finalizatori în apendicele său, unde se spune:

Aproape întotdeauna este mai bine să vă faceți propria curățare în loc să vă bazați pe un finalizator. De asemenea, utilizarea unui finalizator poate lăsa în urmă resurse critice care nu vor fi recuperate pentru o perioadă de timp nedeterminată. Dacă vă gândiți să utilizați un finalizator pentru a vă asigura că resursele importante sunt eliberate în timp util, ar fi bine să vă mai gândiți.

Unai Vivi

Permiteți-mi să adaug ceva la răspunsurile celorlalți.

Dacă puteți importa Apache Commons IO, , ați putea utiliza întotdeauna atât de utilul AutoCloseInputStreams: înfășurați clasele InputStream și apoi folosiți instanța înfășurată, iar aceasta se închide automat de îndată ce se ajunge la sfârșitul intrării sau când fluxul este închis în mod explicit, oricare dintre acestea are loc mai întâi.

lhl

Deoarece FileInputStream implementează finalize() și invocă close() în `finalize.

Deci, atunci când nu este folosit atât de frecvent, nu este nevoie să se închidă FileInputStream