È meglio non .close () all'interno del corpo del metodo API quando viene passato un Reader o InputStream?

4

Ci sono molte domande simili a cui è stata data una risposta. Esempio qui . Tuttavia, hanno entrambi Reader e InputStream all'interno dello stesso ambito o corpo del metodo e pertanto suggeriscono di chiudere l'ultimo della catena ( Reader ) anziché il primo ( InputStream ).

Quindi, per il mio caso particolare, sto costruendo un'API e voglio che gli utenti possano scegliere quale fonte di input usare. Hanno bisogno di flessibilità. Per questo in genere seguo questo tipo di modello:

public class Handler {
  public void handle(BufferedReader in) {
    in.lines().forEach(System.out::println);
  }

  public void handle(InputStream in) {
    handle(new BufferedReader(new InputStreamReader(in)));
  }

  public void handle(Class anchor,String resource) throws IOException {
    try (InputStream in = anchor.getResourceAsStream(resource)) {
            handle(in);
    }
  }

  public void handle(String resource) throws IOException {
    try (InputStream in = ClassLoader.getSystemResourceAsStream(resource)) {
            handle(in);
    }
  }

  public void handle(Path path) throws IOException {
    try (InputStream in = Files.newInputStream(path)) {
            handle(in);
    }
  }

  public void handle(File file) throws IOException {
    try (InputStream in = Files.newInputStream(file.toPath())) {
            handle(in);
    }
  }

  public static void main(String args[]) throws NoSuchMethodException, IOException { 
    Handler h = new Handler();
    h.handle(Handler.class,"/readme.txt");
  }
}

Penso che abbia i seguenti vantaggi:

  • Solo il proprietario della risorsa può chiuderlo. Nel caso di lettore / input, il vantaggio non è così chiaro. Tuttavia, se fosse stato scrittore / prodotto, questo mi avrebbe permesso di far funzionare più funzioni consecutive una dopo l'altra sulla stessa risorsa. Penso che abbia senso come API.
  • Semplice da capire: se passi / possiedi la risorsa, hai la responsabilità di chiuderla.
  • Se passi un nome di risorsa ( String ), è chiaro che l'API dovrà occuparsi sia dell'apertura che della chiusura della risorsa.

Quindi c'è una differenza con gli altri post, sia in situazione, sia su come rispondere:

  • Qui: se Reader o InputStream viene passato come parametro a un metodo di un'API, quindi non .close() su di esso all'interno del corpo del metodo API.
  • Altro: se all'interno dello stesso ambito, InputStream è concatenato con Reader , quindi chiude sempre l'ultimo della catena ( Reader ).

Penso che abbia senso, ma è un modo corretto di gestirlo?

    
posta YoYo 04.02.2016 - 23:05
fonte

1 risposta

1

Direi che nessuno dei due è la soluzione migliore.

Quando hai a che fare con uno Stream o Reader di qualche tipo, allora è implicito che questo è per leggere Input o scrivere Output su alcuni dati o risorse disponibili esternamente. Questa risorsa può o non può essere associata a un file del sistema operativo, quindi chiamando un metodo .close() su di esso significa che potresti anche potenzialmente influenzare qualcosa a livello di sistema operativo.

In generale, se un metodo deve ottenere un flusso o un lettore di qualche tipo, allora la scommessa più sicura è gestire correttamente l'istanziazione del flusso o del lettore da una o più risorse, gestire le eccezioni che potrebbero emergere e finalizzare l'uso delle risorse prima di abbandonare l'ambito della chiamata al metodo.

Se il file o la risorsa è grande o un flusso di dati potenzialmente infinito, allora probabilmente ha senso che l'ambito di un flusso o di un lettore risulti più lungo rispetto all'ambito di un metodo. Se il ciclo di vita Stream o Reader è legato al ciclo di vita di un'istanza di Classe, l'opzione appropriata è che lo Stream o il Reader siano proprietà private della Classe, in modo tale che i metodi dell'istanza della classe possano utilizzarlo e dipendere da esso. Devi fare attenzione qui a ripulire e chiudere le tue risorse, anche se quando quell'istanza di classe viene raccolta in un cestino, raccoglierà anche il tuo stream o Reader. Non credo che ogni implementazione JVM garantisca che il metodo finalize() venga chiamato su garbage collector ma potrei sbagliarmi qui.

La linea di fondo è che è considerato BAD PRACTICE in Java per aprire un flusso o Reader e passarlo come argomento a un metodo. L'unica volta che direi che questo è appropriato è se si dispone di un metodo molto grande e si desidera suddividere il codice in piccoli metodi di supporto, ma anche in questo caso dovrebbero essere metodi di ambito privato e dovrebbero essere documentati. Certamente non vorrei vedere un metodo che accetta questo come un tentativo di parametro di chiuderlo per conto del metodo sottostante in pila. Anche dal punto di vista della revisione del codice, vorrei vedere dove vengono inizializzati i gestori di risorse e in definitiva vedere chiaramente dove sono anche garantiti per essere finalizzati e chiusi.

    
risposta data 17.03.2016 - 17:16
fonte

Leggi altre domande sui tag