[java] snelle equals design probleem

Pagina: 1
Acties:

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Om mijn programma te versnellen ben ik tegen hetvolgende probleem aangelopen..


Stel dat ik het volgende heb
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
VoorbeeldObject {
    private int value;
    
    public TestObject(int value){
        this.value = value;
    }
    
    public boolean equals(Object item){
        if(item == null)
            return false;
        
        if(item == this)
            return true;
            
        if(!(item instanceof VoorbeeldObject))
            return false;
            
        VoorbeeldObject anderVoorbeeldObject = (VoorbeeldObject)item;
        return anderVoorbeeldObject.value == value;
    }
    
    public int hashCode(){
        return value;
    }
    
}

Bij dit object is dus een inhoudelijke equals geimplementeerd, wat je in veel gevallen ook nodig hebt als je met bv collecties wilt werken. (Deze equals is zoals het door sun word voorgeschreven). In dit geval gaat het ook nog redelijk snel maar mijn objecten zijn een stuk gecompliceerder en een inhoudelijke vergelijking kan dus behoorlijk langzaam worden.

In mijn systeem kan het voorkomen dat ik dus meerdere instanties van hetzelfde object krijg en toch blijft het systeem correct functioneren. Om het geheel wat sneller te maken ga ik als ik een nieuw VoorbeeldObject heb gecreerd eerst kijken of er al een andere instantie gemaakt is. Als dat zo is dan maak ik daar gebruik van. Nu kan ik mijn equals vereenvoudigen tot:
code:
1
2
3
    public boolean equals(Object item){
        return item == this;    
    }

Dit is natuurlijk een stuk sneller. Maar nu heb je dus die inhoudelijke vergelijking niet meer. De vraag is hoe ik dit nu correct kan oplossen. Want dit moet al lang een keer zijn uitgevonden.

probleem is dus dat ik soms inhoudelijke vergelijking wil en soms pointer vergelijking. (flag zetten heb ik ook al bedacht :) )

  • Pooh
  • Registratie: April 2001
  • Niet online

Pooh

Lees eens een boek

huh? :?

Wat wil je nu? Of je hebt 2x dezelfde instance, en kunt dus rechtstreeks met == vergelijken, of je hebt twee verschillende instances, en zult dan elk onderdeel van het object moeten vergelijken. Iets anders kan toch niet? :?

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Alarmnummer: Om het geheel wat sneller te maken ga ik als ik een nieuw VoorbeeldObject heb gecreerd eerst kijken of er al een andere instantie gemaakt is.
Je maakt dus gebruik van een object-cache... Doe ik ook in al mijn database-systemen (in combinatie met WeakReferences)
Dit is natuurlijk een stuk sneller. Maar nu heb je dus die inhoudelijke vergelijking niet meer. De vraag is hoe ik dit nu correct kan oplossen. Want dit moet al lang een keer zijn uitgevonden.
Uh, je hebt nu toch ook geen inhoudelijke vergelijking meer nodig? Als je uit gaat van de aanname dat er altijd met 1 object is voor objecten van gelijke waarden is dit de enige zinvolle oplossing. Als je toch nog inhoudelijke vergelijking gaat doen, win je natuurlijk helemaal niets. Of begrijp ik je nu verkeerd :? .

Heb je er trouwens al eens aan gedacht om te vergelijken op hashcode?

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Op dinsdag 22 januari 2002 14:48 schreef Poohbear het volgende:
huh? :?

Wat wil je nu? Of je hebt 2x dezelfde instance, en kunt dus rechtstreeks met == vergelijken, of je hebt twee verschillende instances, en zult dan elk onderdeel van het object moeten vergelijken. Iets anders kan toch niet? :?
Als je met een HashMap/Table werkt dan word eerst mbv de hashcode een bucket uitgezocht en daarna word ieder element bij langs gegaan (met equals) om de juiste te zoeken. Ik kan daar dus geen gebruik maken van de == operator.

  • Pooh
  • Registratie: April 2001
  • Niet online

Pooh

Lees eens een boek

Op dinsdag 22 januari 2002 14:43 schreef Alarmnummer het volgende:
probleem is dus dat ik soms inhoudelijke vergelijking wil en soms pointer vergelijking. (flag zetten heb ik ook al bedacht :) )
Zeg dat dan meteen...

Ik zou equals gewoon de inhoudelijke vergelijking laten doen (zoals sun voorschrijft), en een andere functie gebruiken om de pointer te testen. (Waarom zou je dat in je class zelf willen doen trouwens?)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Op dinsdag 22 januari 2002 14:50 schreef mbravenboer het volgende:

[..]

Je maakt dus gebruik van een object-cache... Doe ik ook in al mijn database-systemen (in combinatie met WeakReferences)
[..]

Uh, je hebt nu toch ook geen inhoudelijke vergelijking meer nodig? Als je uit gaat van de aanname dat er altijd met 1 object is voor objecten van gelijke waarden is dit de enige zinvolle oplossing. Als je toch nog inhoudelijke vergelijking gaat doen, win je natuurlijk helemaal niets. Of begrijp ik je nu verkeerd :? .

Heb je er trouwens al eens aan gedacht om te vergelijken op hashcode?
Je kan niet controleren of objecten gelijk zijn op basis van hashcode :) Zie mijn maffe string monoloog van laatst :) Je kan equals wel versnellen door nog even een
code:
1
2
if(hashCode()!=item.hashCode())
 return false

toe te voegen :)

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
probleem is dus dat ik soms inhoudelijke vergelijking wil en soms pointer vergelijking. (flag zetten heb ik ook al bedacht.
Ah, The Editor weer aan het werk ;) .

flap is een oplossing. Je kunt ook een 'Vergelijker' (desnoods zelfs gewoon de Comparator) intruduceren die vergelijkt. Dat is wellicht een wat schonere oplossing dan een flag.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Je krijgt dus gewoon 2 equals methoden.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    public boolean equals(Object item){
       return item == this;     
    }

    public boolean equalsInternally(Object item){
       if(item == null)
          return false;
           
       if(item == this)
          return true;
                 
       if(!(item instanceof VoorbeeldObject))
          return false;
                 
       VoorbeeldObject anderVoorbeeldObject =     (VoorbeeldObject)item;
         return anderVoorbeeldObject.value == value;
    }

Maar nu kan ik niet op zoek gaan in collecties naar een zelfde instantie omdat collecties gebruik maken van de equals(Object item). Het enigste wat je kan doen is zelf objecten bijlangsgaan en je kan dan geen gebruik maken van bv HashMaps.

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
VoorbeeldZoekObject {
    private int value;
    
    public VoorbeeldZoekObject(int value){
        this.value = value;
    }
    
    public boolean equals(Object item){
        if(item == null)
            return false;
        
        if(item == this)
            return true;
            
        if(!(item instanceof VoorbeeldObject))
            return false;
            
        VoorbeeldObject anderVoorbeeldObject = (VoorbeeldObject)item;
        return anderVoorbeeldObject.value == value;
    }
    
    public int hashCode(){
        return value;
    }   
}

Misschien kan ik zoiets doen. Ik ga hiermee op zoek door een hashmap en ik vind dan mijn VoorbeeldObject. Voorbeeld object die kan gewoon een equals op basis van pointer hebben. Nu maar hopen dat de hashMap

voorbeeldZoekObject.equals(item) doet ipv
item.equals(voorbeeldZoekObject)

moet ik even door de hashmap code kijken.

  • Pooh
  • Registratie: April 2001
  • Niet online

Pooh

Lees eens een boek

Op dinsdag 22 januari 2002 15:01 schreef Alarmnummer het volgende:
Je krijgt dus gewoon 2 equals methoden.

Maar nu kan ik niet op zoek gaan in collecties naar een zelfde instantie omdat collecties gebruik maken van de equals(Object item). Het enigste wat je kan doen is zelf objecten bijlangsgaan en je kan dan geen gebruik maken van bv HashMaps.
Zoals ik al zei, ik zou 't andersom doen:
code:
1
2
public boolean equals(Object item){ hoop; moeilijke; code; }
public boolean equalsInstance(Object item){ item==this; }

Maar dan issie dus wel trager ;(

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Op dinsdag 22 januari 2002 15:05 schreef Poohbear het volgende:

[..]

Zoals ik al zei, ik zou 't andersom doen:
code:
1
2
public boolean equals(Object item){ hoop; moeilijke; code; }
public boolean equalsInstance(Object item){ item==this; }

Maar dan issie dus wel trager ;(
Daar heb ik dus nietzoveel aan :) had ik het net zo goed niet kunnen doen :)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  public Object get(Object key) {
    Iterator i = entrySet().iterator();
    if (key==null) {
        while (i.hasNext()) {
        Entry e = (Entry) i.next();
        if (e.getKey()==null)
            return e.getValue();
        }
    } else {
        while (i.hasNext()) {
        Entry e = (Entry) i.next();
        if (key.equals(e.getKey()))<<==
            return e.getValue();
        }
    }
    return null;
    }

Mooi zo.. het kan dus volgens mij wel zoals ik wil :)

Ik stop in de hashmap een VoorbeeldZoekObject en krijg dan het Voorbeeld object terug en dan maak ik daar gebruik van :)

Jammer dat het design hierdoor een stuk ingewikkelder begint te worden...

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
oplossing :)
IdentityHashMap

precies wat ik wil :) :) :) :) :) :) :) :)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
ben nu van 3.5 seconden naar 2.5 seconden gegaan doordat ik niet meer zovaak een equals aanroep maar met een == werk :) (De IdentityHashMap)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Is er trouwens een naam voor een een instantie uniek te maken, of voor het object dat dat regelt?

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Ik laad al mijn domein-objecten in een database applicatie via een DomainObjectLoader. Deze DomainObjectLoader gebruikt weer een generieke ObjectCache (met geparameterizeerde typen :9~ ). Deze gebruikt weer WeakReferences om het caching mechanisme goed te laten werken. Ik vind deze naamgeving wel duidelijk en zou geen andere 'afspraken' weten.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • The - DDD
  • Registratie: Januari 2000
  • Laatst online: 03-09 16:40
Zoek is naar het Flyweight design pattern. Staat onderandere in het Design Pattern boek van de Gang of Four.

Het pattern dient ervoor om doormiddel van object reuse efficient om te gaan met veel van dezelfde type klassen met dezelfde betekenis.

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Op dinsdag 22 januari 2002 20:32 schreef The - DDD het volgende:
Zoek is naar het Flyweight design pattern. Staat onderandere in het Design Pattern boek van de Gang of Four.

Het pattern dient ervoor om doormiddel van object reuse efficient om te gaan met veel van dezelfde type klassen met dezelfde betekenis.
Ik heb het al opgelost door eerst in een normale hashmap (die gebruik maak van de inhoudelijke equals) te gaan zoeken. Ik maak dus eerst bv een Persoon jan aan. Dan ga ik die opzoeken in die hashmap en als hij er in voorkomt, dan gebruik ik die gevonden instantie. Komt hij niet in de hashmap voor dan plaatst ik hem erin en gebruik hem.

Later maak ik gebruik van IdentityHashMap wat als voordeel heeft dat deze geen equals gebruikt maar de == wat dus een stuk sneller is dan de inhoudelijke equals. Al het zoekwerk daarna word dus allemaal gedaan met de == en als je veel zoekwerk hebt (in mijn geval) dan heb je een stuk performance winst.
Pagina: 1