Ciao Simone,grazie per il link: molto interessante.Neanche io mi trovo
d'accordo, il ragionamento ci sta, ma comunque non giustifica le conclusioni,
soprattutto conclusioni così drastiche.C'è da dire che hanno fatto la stessa
cosa con i ByteBuffer, avendo la decenza di aggiungere il metodo isReadOnly.A
quanto pare è una best practice, con questa logica potevano anche evitare
String e usare solo StringBuffer :)
Grazie ancora per la presentazione, forse non avrai partecipato, ma si è molto
chiacchierato sulle tue parole,non pochi si contorcevano indemoniati
commentando le ultime e prossime novità.
Tra le novità di Java 14 (stranamente poco pubblicizzate da Oracle) ce ne sono
anche di interessanti riguardo Shenandoah,a mio avviso dalla JRE 13 è diventato
un buon candidato a sostituire il G1. I dettagli li puoi trovare
quihttps://developers.redhat.com/blog/2020/03/04/shenandoah-gc-in-jdk-14-part-1-self-fixing-barriers/
Vasco
Il sabato 16 maggio 2020, 13:20:35 CEST, Simone Bordet
[email protected] [it-torino-java-jug]
<[email protected]> ha scritto:
Ciao,
On Sat, May 16, 2020 at 11:54 AM Francesco Vasco [email protected]
[it-torino-java-jug] <[email protected]> wrote:
> Durante l'ultimo interessante incontro di Simone, si è affrontato il tema
> delle interfacce delle collection con metodi opzionali (qualsiasi cosa questo
> voglia dire in OO).
Opzionali nel senso che ci sono, ma poi vengono implementati con
"throw new UnsupportedOperationException()".
> Il punto che vorrei approfondire è che questa scelta avrebbe semplificato,
> altrimenti ci sarebbero state 500 classi (vado a memoria).
> Sono curiosi di questa affermazione, poiché mi sembra una esagerazione, Scala
> ha una sua implementazione con questa differenziazione, Kotlin differenzia le
> interfacce e condivide l'implementazione con Java.
Avevo premesso che stavo dicendo numeri a caso (ho menzionato il
passaggio da 50 a 500 per enfatizzare il discorso).
I numeri più precisi e la discussione sul design si trovano qui:
https://docs.oracle.com/javase/8/docs/technotes/guides/collections/designfaq.html
Il discorso era che è molto difficile fare un design perfetto per
qualcosa usato in modo molto generico e quindi con un sacco di use
cases.
Si devono accettare dei compromessi.
Nelle Java collections hanno accettato i metodi che lanciano
UnsupportedOperationException che se guardate su qualsiasi libro di
teoria OO vengono descritti come un abominio.
E lo hanno fatto per ridurre al minimo il numero di interfacce da
"spiegare" ad uno sviluppatore.
"When all was said and done, we felt that it was a sound engineering
compromise to sidestep the whole issue by providing a very small set
of core interfaces that can throw a runtime exception."
Ora, non è che mi trovi molto d'accordo.
Penso che la soluzione di Kotlin sia un compromesso migliore anche se
non è perfetto neanche quello.
Per fare un esempio, sia Java che Kotlin hanno List.listIterator(int)
che è ovviamente inutilizzabile in ambiente concorrente (l'indice che
viene passato come argomento può non essere più valido quando viene
chiamato listIterator(int)).
Quindi, abbiamo una astrazione abbastanza generica come List che non
può essere usata per implementare una List concorrente.
L'implementazione può "provare" e sperare che l'indice sia buono - ma
rischio di avere non l'elemento che voglio oppure lancio
ArrayIndexOutOfBoundsException, oppure lascio stare e lancio
UnsupportedOperationException.
E allora, vogliamo aggiungere anche le interfacce "NonConcurrent"?
Il discorso che facevamo era proprio sui compromessi.
--
Simone Bordet
---
Finally, no matter how good the architecture and design are,
to deliver bug-free software with optimal performance and reliability,
the implementation technique must be flawless. Victoria Livschitz