UnsupportedOperationException nelle interfacce framework java collections

12

Guardando attraverso il Java Collections Framework, ho notato che alcune delle interfacce hanno il commento (optional operation) . Questi metodi consentono di implementare le classi attraverso un UnsupportedOperationException se semplicemente non vogliono implementare quel metodo.

Un esempio di questo è il metodo addAll in Set Interface .

Ora, come affermato in questa serie di domande, le interfacce sono un contratto definitivo per ciò che l'uso può aspettarsi.

Interfaces are important because they separate what a class does from how it does it. The contract defining what a client can expect leaves the developer free to implement it any way they choose, as long as they uphold the contract.

e

An interface is a description of the actions that an object can do... for example when you flip a light switch, the light goes on, you don't care how, just that it does. In Object Oriented Programming, an Interface is a description of all functions that an object must have in order to be an "X".

e

I think the interface-based approach is significantly nicer. You can then mock out your dependencies nicely, and everything is basically less tightly coupled.

Qual è il punto di un'interfaccia?

Quali sono le interfacce?

Interfaccia + estensione (mixin) vs classe base

Dato che lo scopo delle interfacce è definire un contratto e rendere le vostre dipendenze liberamente accoppiate, non vi sono alcuni metodi che lanciano un tipo di sconfitta allo scopo di UnsupportedOperationException ? Significa che non posso più passare un Set e usare solo addAll . Piuttosto, devo sapere quale implementazione di Set I è stata passata, quindi posso sapere se posso usare addAll o no. Mi sembra abbastanza inutile.

Quindi qual è il punto di UnsupportedOperationException ? Sta solo recuperando il codice legacy e hanno bisogno di ripulire le loro interfacce? O ha uno scopo più sensuale che mi manca?

    
posta MirroredFate 10.07.2015 - 19:40
fonte

2 risposte

12

Guarda le seguenti interfacce:

Queste interfacce dichiarano i metodi di muting come facoltativi. Questo sta implicitamente documentando il fatto che la classe Collections è in grado di restituire implementazioni di quelle interfacce che sono immutabili: cioè, quelle operazioni di mutazione opzionali sono garantite per fallire. Tuttavia, in base al contratto nel JavaDoc, tutte le implementazioni di tali interfacce devono consentire le operazioni di lettura. Ciò include le implementazioni "normali" come HashSet e LinkedList , nonché i wrapper immutabili in Collections .

Contrasto con le interfacce della coda:

Queste interfacce non specificano eventuali operazioni opzionali: una coda, per definizione, è progettata per offrire e interrogare gli elementi in un modo FIFO. Una coda immutabile è utile tanto quanto un'auto senza ruote.

Un'idea comune che si presenta ripetutamente è avere una gerarchia di ereditarietà con oggetti sia mutevoli che immutabili. Tuttavia, questi hanno tutti degli inconvenienti. La complessità confonde le acque senza risolvere il problema.

  • Un ipotetico Set potrebbe avere le operazioni di lettura e una subinterfaccia MutableSet potrebbe avere le operazioni di scrittura. Liskov ci dice che un MutableSet potrebbe quindi essere passato a qualsiasi cosa abbia bisogno di un Set . All'inizio sembra ok, ma si consideri un metodo che si aspetta che il set sottostante non venga modificato durante la lettura: sarebbe possibile che due thread usino lo stesso set e violino l'invariante dell'insieme che non cambia. Ciò potrebbe causare un problema, ad es. se un metodo legge un elemento dal set due volte ed è lì la prima volta ma non la seconda volta.

  • Set non può avere implementazioni dirette, avendo invece MutableSet e ImmutableSet come sottointerfacce che vengono poi utilizzate per implementare le classi. Questo ha lo stesso problema di prima: a un certo punto della gerarchia, un'interfaccia ha invarianti in conflitto. Uno dice "questo set deve essere mutabile" e l'altro dice "questo set non può cambiare".

  • Potrebbero esserci due gerarchie completamente separate per strutture di dati mutabili e immutabili. Questo aggiunge un ton di complessità extra per quello che finisce per essere un guadagno molto scarso. Questo ha anche la debolezza specifica dei metodi che non tengono conto della mutabilità (ad esempio, voglio solo iterare una lista) ora devono supportare due interfacce separate. Poiché Java è tipizzato staticamente, questo significa metodi extra per gestire entrambe le gerarchie dell'interfaccia.

  • Potremmo avere una singola interfaccia e consentire alle implementazioni di generare eccezioni se un metodo non è applicabile ad esso. Questa è la strada che Java ha preso, e ha più senso. Il numero di interfacce è ridotto al minimo e non ci sono invarianti di mutabilità perché l'interfaccia documentata non fornisce garanzie sulla mutabilità in entrambi i casi . Se è richiesto un invariant di immutabilità, utilizzare i wrapper in Collections . Se un metodo non ha bisogno di cambiare una collezione, semplicemente non cambiarlo. Lo svantaggio è che un metodo non può garantire che una raccolta non cambierà in un altro thread se viene fornita una raccolta dall'esterno, ma questa è una preoccupazione del metodo chiamante (o del suo metodo di chiamata) comunque.

Lettura correlata: Perché Java 8 non include collezioni immutabili?

    
risposta data 10.07.2015 - 20:08
fonte
2

È fondamentalmente YAGNI. Tutte le raccolte concrete nella libreria standard sono modificabili, implementando o ereditando le operazioni opzionali. Non si preoccupano delle collezioni immutabili per scopi generali e nemmeno la stragrande maggioranza degli sviluppatori Java. Non creeranno un'intera gerarchia di interfacce solo per le raccolte immutabili, quindi non includeranno alcuna implementazione.

D'altra parte, ci sono alcuni valori per scopi speciali o collezioni "virtuali" che potrebbero essere molto utili come immutabili, come set vuoto e nCopies . Inoltre, ci sono collezioni immutabili di terze parti (come quelle di Scala), che potrebbero voler chiamare il codice Java esistente, così hanno lasciato aperta la possibilità di collezioni immutabili nel modo meno dirompente.

    
risposta data 10.07.2015 - 20:39
fonte

Leggi altre domande sui tag