D: Perché non sostenere l'immutabilità direttamente nelle interfacce di raccolta di base in modo che si può fare via con le operazioni opzionali (e UnsupportedOperationException)?
A: Questa è la decisione di progettazione più controverso nell'intera API. Chiaramente, il controllo del tipo statico (tempo di compilazione) è altamente auspicabile ed è la norma in Java. L'avremmo supportato se avessimo creduto che fosse fattibile. Sfortunatamente, i tentativi di raggiungere questo obiettivo causano un'esplosione delle dimensioni della gerarchia dell'interfaccia e non riescono a eliminare la necessità di eccezioni di runtime (sebbene la riducano in modo sostanziale).
Doug Lea, che ha scritto un popolare pacchetto di raccolte Java che riflette le differenze di mutabilità nella sua gerarchia di interfacce, non crede più che sia un approccio praticabile, basato sull'esperienza utente con il suo pacchetto di raccolte. Nelle sue parole (dalla corrispondenza personale) "Per quanto mi addolori dirlo, la tipizzazione statica forte non funziona per le interfacce di raccolta in Java."
Per illustrare il problema nei dettagli cruenti, si supponga di voler aggiungere la nozione di modificabilità alla Gerarchia. Sono necessarie quattro nuove interfacce: ModifiableCollection, ModifiableSet, ModifiableList e ModifiableMap. Ciò che prima era una semplice gerarchia ora è un'eterea disordinata. Inoltre, è necessaria una nuova interfaccia Iterator da utilizzare con le raccolte non modificabili, che non contengono l'operazione di rimozione. Ora puoi eliminare UnsupportedOperationException? Sfortunatamente no.
Considerare gli array. Implementano la maggior parte delle operazioni di elenco, ma non rimuovono e aggiungono. Sono elenchi di "dimensioni fisse". Se si desidera acquisire questa nozione nella gerarchia, è necessario aggiungere due nuove interfacce: VariableSizeList e VariableSizeMap. Non è necessario aggiungere VariableSizeCollection e VariableSizeSet, perché sarebbero identici a ModifiableCollection e ModifiableSet, ma è possibile scegliere di aggiungerli comunque per motivi di coerenza. Inoltre, è necessaria una nuova varietà di ListIterator che non supporta le operazioni di aggiunta e rimozione, per accompagnare l'Elenco non modificabile. Ora abbiamo fino a dieci o dodici interfacce, oltre a due nuove interfacce Iterator, invece delle nostre quattro originali. Abbiamo finito? No.
Considerare i registri (come i registri degli errori, i registri di controllo e i periodici per gli oggetti dati recuperabili). Sono sequenze naturali solo in append, che supportano tutte le operazioni List tranne che per remove e set (replace).Richiedono una nuova interfaccia principale e un nuovo iteratore.
E che dire di collezioni immutabili, al contrario di quelle non modificabili? (Ad esempio, Raccolte che non possono essere modificate dal cliente E non cambieranno mai per nessun altro motivo). Molti sostengono che questa è la distinzione più importante di tutti, poiché consente a più thread di accedere a una raccolta contemporaneamente senza necessità di sincronizzazione. L'aggiunta di questo supporto alla gerarchia dei tipi richiede altre quattro interfacce.
Ora abbiamo una ventina di interfacce e cinque iteratori, ed è quasi certo che ci sono ancora raccolte in pratica che non si adattano perfettamente a nessuna delle interfacce. Ad esempio, le viste di raccolta restituite da Map sono raccolte di solo eliminazione naturali. Inoltre, ci sono raccolte che rifiuteranno determinati elementi in base al loro valore, quindi non abbiamo ancora eliminato le eccezioni del runtime.
Quando tutto è stato detto e fatto, abbiamo ritenuto che si trattasse di un valido compromesso tecnico per aggirare l'intero problema fornendo un insieme molto piccolo di interfacce principali che possono generare un'eccezione di runtime.
* "L'interfaccia era un contratto in modo da poter utilizzare la funzionalità di imposizione tra diverse implementazioni" * - Non è forse qualcosa con cui le interfacce di raccolta funzionano correttamente? L'utilizzo di eccezioni come parte della funzionalità è forse impopolare, ma è una funzionalità linguistica e non c'è nulla di opzionale quando si utilizza o si implementa una raccolta correttamente. Devi lanciare/aspettarti delle eccezioni. Ho desiderato interfacce più sottili o almeno metodi come '.supportsRemoval()' abbastanza spesso però. 'ImmutableSet' estende' Set' in quanto specifica quali metodi sono ora garantiti per il lancio. – zapl