hashCode e hashMap

16 views
Skip to first unread message

Tiziano Lattisi

unread,
Apr 26, 2012, 4:10:48 PM4/26/12
to jug...@googlegroups.com
Ciao,
le entità create da Netbeans hanno un metodo di hash predefinito che
ha questa forma:

public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}

Che può essere una scelta intelligente, visto che non basandosi
sull'indirizzo di memoria
dell'istanza, permettono ad esempio di recuperare da un hashMap
utilizzando come chiave
un'entità che tra "get" e "set" ha cambiato il suo indirizzo di
memoria (caso tipico appunto
in jpa).

C'è però un brutto effetto collaterale: due entità ancora transienti
usate come chiave in un
hashMap mi restituiscono lo stesso valore.

Una prima soluzione potrebbe essere:


public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : super.hashCode());
return hash;
}

Il "trucco" funziona, ma non mi soddisfa.
Vorrei mantenere il metodo hashCode così come me lo costruisce
Netbeans, ma "istruire"
la mia hashMap affinché funzioni in modo analogo, utilizzando quindi
hashCode se restituisce
un valore diverso da 0, altrimenti il suo super.hashCode.

Qualche idea su come procedere? Una mezza idea già l'avrei, ma ho
paura che ci sia
qualcosa di meno contorto di ciò a cui sto pensando...

ciao!
t.

Davide

unread,
Apr 26, 2012, 4:28:49 PM4/26/12
to jug...@googlegroups.com

Ciao Tiziano,

partirei dalla domanda: perch� vuoi mettere degli oggetti jpa
come chiave di una hashmap?

On 04/26/2012 10:10 PM, Tiziano Lattisi wrote:
> Ciao,
> le entit� create da Netbeans hanno un metodo di hash predefinito che
> ha questa forma:
>
> public int hashCode() {
> int hash = 0;
> hash += (id != null ? id.hashCode() : 0);
> return hash;
> }
>
> Che pu� essere una scelta intelligente, visto che non basandosi
> sull'indirizzo di memoria
> dell'istanza, permettono ad esempio di recuperare da un hashMap
> utilizzando come chiave
> un'entit� che tra "get" e "set" ha cambiato il suo indirizzo di
> memoria (caso tipico appunto
> in jpa).
>
> C'� per� un brutto effetto collaterale: due entit� ancora transienti
> usate come chiave in un
> hashMap mi restituiscono lo stesso valore.
>
> Una prima soluzione potrebbe essere:
>
>
> public int hashCode() {
> int hash = 0;
> hash += (id != null ? id.hashCode() : super.hashCode());
> return hash;
> }
>
> Il "trucco" funziona, ma non mi soddisfa.
> Vorrei mantenere il metodo hashCode cos� come me lo costruisce
> Netbeans, ma "istruire"
> la mia hashMap affinch� funzioni in modo analogo, utilizzando quindi
> hashCode se restituisce
> un valore diverso da 0, altrimenti il suo super.hashCode.
>
> Qualche idea su come procedere? Una mezza idea gi� l'avrei, ma ho
> paura che ci sia
> qualcosa di meno contorto di ci� a cui sto pensando...
>
> ciao!
> t.
>

Tiziano Lattisi

unread,
Apr 26, 2012, 4:36:05 PM4/26/12
to jug...@googlegroups.com
Ciao Davide,
si tratta di una cache interposta tra un modello del toolkit grafico Qt,
e i dati sottostanti.
Il modello interroga la cache, molto più veloce, fintanto che le entità
sottostanti non vengono invalidate.


Il 26 aprile 2012 22:28, Davide <d...@vide.bz> ha scritto:
> Ciao Tiziano,
>
> partirei dalla domanda: perchè vuoi mettere degli oggetti jpa

Davide

unread,
Apr 26, 2012, 4:38:37 PM4/26/12
to jug...@googlegroups.com

Se si tratta di una cache ... conosci la identity hashmap?

On 04/26/2012 10:36 PM, Tiziano Lattisi wrote:
> Ciao Davide,
> si tratta di una cache interposta tra un modello del toolkit grafico Qt,
> e i dati sottostanti.
> Il modello interroga la cache, molto pi� veloce, fintanto che le entit�
> sottostanti non vengono invalidate.
>
>
> Il 26 aprile 2012 22:28, Davide<d...@vide.bz> ha scritto:
>> Ciao Tiziano,
>>
>> partirei dalla domanda: perch� vuoi mettere degli oggetti jpa

Tiziano Lattisi

unread,
Apr 26, 2012, 4:43:14 PM4/26/12
to jug...@googlegroups.com
Sì, ma in questo modo avrei il comportamento che vorrei per le entità
transienti, ma non per le persistenti. :-(

Davide

unread,
Apr 26, 2012, 4:45:01 PM4/26/12
to jug...@googlegroups.com

Ma la cache per quelli persistenti non la gestisce gi� per esempio hibernate?
Non c'� una cache di secondo livello?

On 04/26/2012 10:43 PM, Tiziano Lattisi wrote:
> S�, ma in questo modo avrei il comportamento che vorrei per le entit�

Tiziano Lattisi

unread,
Apr 26, 2012, 4:49:38 PM4/26/12
to jug...@googlegroups.com
Non è una cache per le entità stesse, ma piuttosto per degli Item
che ne gestiscono l'interazione con il layer grafico, che oltre al valore
per colonna "sanno" alcune cose in più.

Un po' difficile da spiegare, il codice sarebbe questo:

http://code.google.com/p/pypapi/source/browse/src/com/axiastudio/pypapi/ui/TableModel.java#163

per ora, se l'entità non è persistente, non metto in cache i suoi Item, e
li calcolo ad ogni bisogno.


Il 26 aprile 2012 22:45, Davide <d...@vide.bz> ha scritto:
>
> Ma la cache per quelli persistenti non la gestisce già per esempio
> hibernate?
> Non c'è una cache di secondo livello?

Vítor Estêvão Silva Souza

unread,
Apr 26, 2012, 4:57:14 PM4/26/12
to jug...@googlegroups.com
2012/4/26 Tiziano Lattisi <tiziano...@gmail.com>

C'è però un brutto effetto collaterale: due entità ancora transienti
usate come chiave in un
hashMap mi restituiscono lo stesso valore.


Meno male che ti è capitato solo questo, perché c'è un altro effetto molto bruttino che ho messo ore per capire: un'entità ancora transiente sul HashMap (oppure HashSet) se diventa transiente cambia il valore di ritorno del hashCode(), e quindi si trova nella posizione sbagliata della collection!

Quindi, potenzialmente:

collection.contains(o); // true
entityManager.persist(o);
collection.contains(o); // false (!!)

Secondo me, una funzione hashCode() che cambia valore di ritorno è maligna (evil!). Io preferisco assegnare all'oggetto un UUID dalla sua creazione e non cambiarlo mai. Guarda questa @MappedSuperclass:

https://github.com/vitorsouza/Sigme/blob/master/src/br/com/engenhodesoftware/util/ejb3/domain/DomainObjectSupport.java

Sono 40 caratteri in più per ogni oggetto nel database (e in memoria), ma per non pensarci più nel problema secondo me vale la pena. Ci sono quelli che addirittura propongono che l'UUID sia la primary key degli oggetti nel database. Io preferisco mantenere un Long con generazione automatica. Vedi tu cosa preferisci...

- Vítor

Tiziano Lattisi

unread,
Apr 26, 2012, 5:20:21 PM4/26/12
to jug...@googlegroups.com
2012/4/26 Vítor Estêvão Silva Souza <vitor...@gmail.com>:
> Meno male che ti è capitato solo questo, perché c'è un altro effetto molto
> bruttino che ho messo ore per capire: un'entità ancora transiente sul
> HashMap (oppure HashSet) se diventa transiente cambia il valore di ritorno
> del hashCode(), e quindi si trova nella posizione sbagliata della
> collection!

Ah, non male, questo me lo annoto. ;-)
Interessante l'approccio che proponi, ma il mio framework ha come mandatory
il doversi appoggiare su un qualunque layer jpa "così come salta fuori
dall'ide".

ciao!
t.

Simone Bordet

unread,
Apr 26, 2012, 5:46:24 PM4/26/12
to jug...@googlegroups.com
Ciao,

2012/4/26 Tiziano Lattisi <tiziano...@gmail.com>:
> 2012/4/26 Vítor Estêvão Silva Souza <vitor...@gmail.com>:
>> Meno male che ti è capitato solo questo, perché c'è un altro effetto molto
>> bruttino che ho messo ore per capire: un'entità ancora transiente sul
>> HashMap (oppure HashSet) se diventa transiente cambia il valore di ritorno
>> del hashCode(), e quindi si trova nella posizione sbagliata della
>> collection!
>
> Ah, non male, questo me lo annoto. ;-)

E' veramente importante, però.
Il contratto di hashCode() è che non deve mai cambiare per 2
invocazioni in tempi diversi.

> Interessante l'approccio che proponi, ma il mio framework ha come mandatory
> il doversi appoggiare su un qualunque layer jpa "così come salta fuori
> dall'ide".

Le tue entità devono avere qualche "natural id", immutabile e noto,
sul quale devi basare l'hashcode.
Per esempio una entità user potrebbe avere come natural id l'email, o
il codice fiscale, ecc.

Se non ce l'hanno, forse devi ripensare il modello dati.

Nota che mettere in cache applicativa entità detached è di norma una
pessima idea.

Prova a vedere se te la cavi mettendo in cache solo i metadati
associati alle entity, cioè i getter/setter, property type, ecc.

Tra parentesi, stai percorrendo una strada che - per esempio in Swing
- si è dimostrata problematica dal punto di vista delle performances:
quella di rappresentare il contenuto di una cella di una tabella con
un oggetto diverso per ogni cella.
In Swing hanno usato un approccio diverso, i CellRenderers, che scala
molto meglio.

Simon
--
http://cometd.org
http://intalio.com
http://bordet.blogspot.com
----
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

Davide

unread,
Apr 26, 2012, 6:17:20 PM4/26/12
to jug...@googlegroups.com
On 04/26/2012 11:46 PM, Simone Bordet wrote:
> Le tue entit� devono avere qualche "natural id", immutabile e noto,
> sul quale devi basare l'hashcode.
> Per esempio una entit� user potrebbe avere come natural id l'email, o
> il codice fiscale, ecc.

Ciao Simone,

in banca dati usavo mettere il codice fiscale come id naturale univoco
ma di solito non l'ho messo anche immutabile. Di solito immutabile era
un id di sistema che veniva usato anche per le fk.
Sai "quante" segretarie fai incavolare con il codice fiscale o un email immutabile ;-)
(nel senso che qualche errore di battitura poteva capitare ...)

Tiziano Lattisi

unread,
Apr 26, 2012, 6:41:24 PM4/26/12
to jug...@googlegroups.com
Ti sei perso un pezzo. ;-)
Non sono le entità ad essere inserite in cache. Le entità fanno solo da chiave.
> --
> You received this message because you are subscribed to the Google Groups "JUG Trentino Alto Adige Suedtirol" group.
> To post to this group, send email to jug...@googlegroups.com.
> To unsubscribe from this group, send email to jugtaa+un...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/jugtaa?hl=en.
>

Simone Bordet

unread,
Apr 26, 2012, 7:10:33 PM4/26/12
to jug...@googlegroups.com
2012/4/27 Tiziano Lattisi <tiziano...@gmail.com>:
> Ti sei perso un pezzo. ;-)
> Non sono le entità ad essere inserite in cache. Le entità fanno solo da chiave.

Non mi sono perso nulla: le tue entity sono referenziate da una cache.
Che siano chiavi o valori, dal punto di vista del lifecycle delle
entity, è lo stesso.
Oppure fai come vuoi, *forse* il tuo codice funzionerà, buona fortuna.

Tiziano Lattisi

unread,
Apr 27, 2012, 2:24:11 AM4/27/12
to jug...@googlegroups.com
Il 27 aprile 2012 01:10, Simone Bordet <sbo...@intalio.com> ha scritto:
> Oppure fai come vuoi, *forse* il tuo codice funzionerà, buona fortuna.

Mi dispiace di constatare come tu sia più pronto a mettere in dubbio il
funzionamento del mio codice, piuttosto che mettere in dubbio di aver
capito effettivamente *cosa* fa il mio codice.

A tuo vantaggio c'è il fatto che puoi scaricare i sorgenti e renderti
direttamente
conto di come stanno le cose.

A mio svantaggio c'è il fatto che i sorgenti del tuo cervello non ci sono,
e quindi non so da quali presupposti scende la tua critica.

Apprezzo in ogni caso il tuo contributo alla discussione. Se vorrai potrò
fornirti qualche informazione in più, solo se ci sarà la possibilità di farlo
senza generare ulteriore rumore sulla lista.

Buona giornata
t.
Reply all
Reply to author
Forward
0 new messages