Visualizzazione dei risultati da 1 a 8 su 8

Hybrid View

  1. #1
    Quote Originariamente inviata da andbin Visualizza il messaggio
    Alt. Se list è di tipo List<Highscore>

    allora la riga

    list.add(ostream.readObject());

    NON ti compila proprio!
    Si, perdonami,ci stavo lavorando con i generici, copiandola qui ho solo cambiato il tipo.

    Speravo ci fosse una maniera più semplice fornita già dalla readObject() >.<
    Procederò con la modalità "b" da te proposta, mi sembra quella più intuitiva e che avrei fatto io.
    Grazie ancora, gentilissimo e limpido nella spiegazione
    Ultima modifica di Mirco993; 18-06-2018 a 19:43

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da Mirco993 Visualizza il messaggio
    Speravo ci fosse una maniera più semplice fornita già dalla readObject() >.<
    No, purtroppo il readObject​() da solo non ti può aiutare in questo.

    Se puoi usare almeno Java 9 c'è una funzionalità nuovissima che si potrebbe usare: la possibilità di passare un "filter" (ObjectInputFilter) al ObjectInputStream che serve per effettuare una validazione sullo stream. Questa funzionalità è stata introdotta principalmente per proteggersi dagli "attacchi" derivanti da stream fatti ad hoc per "impallare" la de-serializzazione o per altre cose malevole.

    Quote Originariamente inviata da Mirco993 Visualizza il messaggio
    Procederò con la modalità "b" da te proposta, mi sembra quella più intuitiva e che avrei fatto io.
    In entrambi i modi a) e b) che ho detto, ad un certo punto devi comunque prevedere un cast, che può naturalmente anche fallire (ClassCastException). Ed è un caso che devi considerare perché vorrebbe dire che lo stream è "malformato".

    Comunque se scegli la b) la forma del metodo (non guardare il nome, quello lo scegli tu) dovresti farla:

    public <T> List<T> deserializeItems(Class<T> aClass)

    Quindi se gli passi un class "literal" come Highscore.class (che è di tipo Class<Highscore>) il compilatore dedurrà che il tipo restituito da quella invocazione è un List<Highscore> e quindi puoi assegnare il risultato direttamente ad una variabile List<Highscore> senza alcun cast o altro che non sia type-safe.


    P.S. vedo che il file lo prendi da this.fileName, quindi avrai di certo una classe di cui crei una istanza. La type variable <T> la puoi mettere volendo a livello di classe (e il Class lo passeresti al costruttore). Dipende dal "design" che intendi fare ...
    Ultima modifica di andbin; 18-06-2018 a 21:39
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    Grazie andbin.
    Ieri, lavorandoci un pò su, ho tirato fuori questo.
    codice:
    public List<X> readElement(Class<? extends X> cl, String fileName){
            List<X> list = new ArrayList<>();
    
            try (
                    final InputStream file = new FileInputStream (fileName);
                    final InputStream bstream = new BufferedInputStream (file);
                    final ObjectInputStream ostream = new ObjectInputStream (bstream);
                    )
            {
                while (true) {
                    Object obj = ostream.readObject();
                        list.add(cl.cast(obj));
                }
            } catch (EOFException e) {
                System.out.println("Ok: file finito, esce");
            } catch (FileNotFoundException e) {
                System.out.println("Ok: file non trovato, lo crea");
                File f = new File(fileName);
                try {
                    f.createNewFile();
                } catch (IOException e1) {
                    /*Non entra mai qui*/
                    e1.printStackTrace();
                }
            } catch (IOException e) {
                System.out.println("Errore: file corrotto");
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (ClassCastException e) {
                System.out.print("Errore: cast errato");
            }
            
            return list;
            
        }
    Ho deciso, come hai giustamente fatto notare, che era poco intuitivo passare il file, o comunque il path, al costruttore.
    Così. istanziando un solo oggetto della classe, posso scrivere e leggere da qualunque file senza vincoli (mi è venuto il dubbio...non è forse meglio farli statici a sto punto? Al costruttore alla fine non passo nulla)


    Quote Originariamente inviata da andbin Visualizza il messaggio
    public <T> List<T> deserializeItems(Class<T> aClass)
    Ero partito anche io così, ma ho riscontrato un problema.
    Quando vado a istanziare la classe, se provo a passare al metodo una classe diversa da quella utilizzata per la creazione, nemmeno mi compila.
    Per intenderci:
    codice:
    ReaderWriter<Highscore> rw = new ReaderWriter<>();
    rw.readElement(Highscore.class, "miofile.txt"); // fino qui tutto ok
    rw.readElement(ClasseABC.class, "miofile.txt");//non mi compila nemmeno
    Notato questo, sono arrivato alla soluzione sopra (anche se non mi convince troppo).
    Adesso è così:
    codice:
    ReaderWriter<Object> rw = new ReaderWriter<>();
    rw.readElement(Highscore.class, "miofile.txt");
    rw.readElement(ClasseABC.class, "miofile.txt");
    rw.readElement(ClasseABCDEF.class, "miofile.txt");
    Quindi, ricapitolando.
    Così può andare bene o c'è un errore concettuale di fondo? (Il fatto di istanziare la classe come ReaderWriter<Object> mi sembra un "trucco", non una soluzione)
    Però se non scrivo "Object" dovrei istanziare un ReaderWriter per ogni classe, e se devo istanziare un ReaderWriter per ogni classe, inutile che gli passo una classe come parametro
    Sarebbe meglio cambiare facendo diventare tutto statico?
    Grazie
    Ultima modifica di Mirco993; 19-06-2018 a 09:53

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da Mirco993 Visualizza il messaggio
    Ieri, lavorandoci un pò su, ho tirato fuori questo.
    Ok ma .. vediamo alcune questioni:

    - meno importante, hai usato X come type variable. Nulla di male o errato ma convenzionalmente si usa T (o E nel caso delle collezioni). O altre lettere in casi più particolari (es. K, V per le map). La X è usata molto raramente (c'è un caso d'uso, in Java 8 la nuova classe Optional ha il orElseThrow che ha una type variable <X extends Throwable> dedicata appunto alla exception).

    - Il ? extends X va bene, così è semplicemente più "ampio". Se passi un Highscore.class, l'inferenza dei tipi permette ad esempio di assegnare ad un List<Object> (perché logicamente qualunque Highscore ci sta in una lista di Object!).
    Senza il extends, se passi Highscore.class, allora devi assegnare ad un List<Highscore> . Tutto qui.

    - La gestione delle eccezioni è un po' fumosa. Sarebbe meglio far uscire l'eccezione fuori dal metodo. E se vogliamo fare i fini, sarebbe anche buono creare una eccezione di più alto livello che incapsula l'eccezione di più basso livello.

    - il fatto di creare il file ... no, non è buono. Non è readElement che dovrebbe occuparsene.

    Quote Originariamente inviata da Mirco993 Visualizza il messaggio
    Ho deciso, come hai giustamente fatto notare, che era poco intuitivo passare il file, o comunque il path, al costruttore.
    No, nel P.S. di prima non dicevo questo! Intendevo che non so (sapevo) come avevi fatto il design della classe e che ci possono essere varie forme possibili.

    Quote Originariamente inviata da Mirco993 Visualizza il messaggio
    Così. istanziando un solo oggetto della classe, posso scrivere e leggere da qualunque file senza vincoli (mi è venuto il dubbio...non è forse meglio farli statici a sto punto? Al costruttore alla fine non passo nulla)

    Ero partito anche io così, ma ho riscontrato un problema.
    Quando vado a istanziare la classe, se provo a passare al metodo una classe diversa da quella utilizzata per la creazione, nemmeno mi compila.
    Per intenderci:
    codice:
    ReaderWriter<Highscore> rw = new ReaderWriter<>();
    rw.readElement(Highscore.class, "miofile.txt"); // fino qui tutto ok
    rw.readElement(ClasseABC.class, "miofile.txt");//non mi compila nemmeno
    Notato questo, sono arrivato alla soluzione sopra (anche se non mi convince troppo).
    Adesso è così:
    codice:
    ReaderWriter<Object> rw = new ReaderWriter<>();
    rw.readElement(Highscore.class, "miofile.txt");
    rw.readElement(ClasseABC.class, "miofile.txt");
    rw.readElement(ClasseABCDEF.class, "miofile.txt");
    Allora qui è meglio chiarire, perché stai facendo confusione.

    Se dichiari la type variable al livello della classe ReaderWriter (che quindi diventa "generica"), va bene, è una scelta possibile. Ma così vai a fissare anche il tipo di ritorno di readElement che è List<X>. Se nell'uso concreto fai un ReaderWriter<Object>, allora vai a fissare che readElement ritorna un List<Object>. Certo ... con lo STESSO oggetto ReaderWriter<Object> puoi invocare readElement con ClasseABC.class e poi un'altra invocazione con ClasseXYZ.class. Ma in uscita hai un List<Object> e questo NON è poi molto utile.

    Se fai un ReaderWriter<Highscore> allora è abbastanza chiaro che quella istanza la dovrai usare solo per leggere oggetti Highscore (quindi List<Highscore>). Per trattare un'altra classe, dovrai creare un'altra istanza, parametrizzata diversamente.
    Se non è questo che vuoi ... non è quello il design giusto!

    Poi c'è anche la questione del filename. Se non lo passi al costruttore, allora le istanze di ReaderWriter a cosa servono? O per dire meglio: due istanze di ReaderWriter in cosa si distinguerebbero e per cosa? Appunto .... Poi magari al momento potrebbero non avere alcun "stato" ma magari in futuro potrebbero avere qualche configurazione o dato specifico per quella istanza.

    Quote Originariamente inviata da Mirco993 Visualizza il messaggio
    Sarebbe meglio cambiare facendo diventare tutto statico?
    Tecnicamente sì, puoi rendere readElement un metodo statico (di "utilità") che è "generico" e riceve il filename.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2026 vBulletin Solutions, Inc. All rights reserved.