SlideShare une entreprise Scribd logo
1  sur  15
Télécharger pour lire hors ligne
@blep#DevoxxFrEqHc
RÉVISION DES FONDAMENTAUX :
EQUALS ET HASHCODE C'EST IMPORTANT
Brice LEPORINI
@blep
Indépendant
http://the-babel-tower.github.io/
@blep#DevoxxFrEqHc
Pourquoi?
•Les devs sont rarement affûtés
sur cette problématique
•La plupart des
implémentations sont buggées
@blep#DevoxxFrEqHc
L’opérateur ==
•Permet de comparer des types primitifs
•Utiliser == sur les objets ne permet que de
vérifier que deux références pointent sur la
même instance
@blep#DevoxxFrEqHc
java.lang.Object#equals
java.lang.Object#equals = ==
@blep#DevoxxFrEqHc
@Getter @Setter

private static class User{

private String name;

}





@Test

public void testEquals() {

final User user1 = new User();

user1.setName("test");



final User user2 = new User();

user2.setName("test");



assertThat(user1.equals(user1)).isTrue(); //Reflexive

assertThat(user2.equals(user2)).isTrue(); //Reflexive



assertThat(user1.equals(null)).isFalse();



assertThat(user1.equals(user2)).isTrue(); // —> Fails



}

java.lang.Object#equals
@blep#DevoxxFrEqHc
Redéfinir equals
• Seul moyen de vérifier que deux instances distinctes sont
fonctionnellement équivalentes
@blep#DevoxxFrEqHc
@Getter @Setter @ToString

private static class User{

private String name;



@Override

public boolean equals(Object obj) {

if (this == obj) return true;

if( ! (obj instanceof User) ) return false;



User other = (User) obj;



return this.name !=null ?
this.name.equals(other.name) : this.name == other.name;

}

}

@Test

public void should_be_equals() {

final User user1 = new User();

user1.setName("bali");



final User user2 = new User();

user2.setName("bali");



final User user3 = new User();

user3.setName("bali");



/* Reflexive */

assertThat(user1.equals(user1)).isTrue();

assertThat(user2.equals(user2)).isTrue();

assertThat(user3.equals(user3)).isTrue();



/* Symmetric */

assertThat(user1.equals(user2)).isTrue();

assertThat(user2.equals(user1)).isTrue();



/* Transitive */

assertThat(user2.equals(user3)).isTrue();

assertThat(user1.equals(user3)).isTrue();



assertThat(user1.equals(null)).isFalse();

assertThat(user2.equals(null)).isFalse();

assertThat(user3.equals(null)).isFalse();

}
Redéfinir equals
@blep#DevoxxFrEqHc
@Test

public void testHashMap() {

final User user1 = new User();

user1.setName("bali");



final User user2 = new User();

user2.setName("bali");



final Map<User, Integer> map = new HashMap<>();

map.put(user1, 2);



assertThat(map).hasSize(1);

assertThat(map.keySet().iterator().next()).isEqualTo(user2);

assertThat(map.values().iterator().next()).isEqualTo(2);

assertThat(map).containsEntry(user2, 2); // —> fails

}

@Test

public void testHashSet() {

final User user1 = new User();

user1.setName("bali");



final User user2 = new User();

user2.setName("bali");



final Set<User> users = new HashSet<>();

users.add(user1);



assertThat(users.iterator().next()).isEqualTo(user2);

assertThat(users.contains(user2)).isTrue(); // -> fails

}

@Test

public void should_not_contain_doubles() {

final User user1 = new User();

user1.setName("bali");



final User user2 = new User();

user2.setName("bali");



final Set<User> users = new HashSet<>();

users.add(user1);

users.add(user2);



assertThat(user1.equals(user2)).isTrue();

assertThat(users).hasSize(1); // —> fails



}

Généralement —> systématiquement
java.lang.AssertionError:
Expecting:
<{_01BasicEquals.User(name=bali)=2}>
to contain:
<[MapEntry[key=_01BasicEquals.User(name=bali), value=2]]>
but could not find:
<[MapEntry[key=_01BasicEquals.User(name=bali), value=2]]>
@blep#DevoxxFrEqHc
HashCode
• Valeur entière représentant la réduction d’un objet
@blep#DevoxxFrEqHc
Hash CollectionsUser1#hashCode
User1, 2
hashCodes
User1#hashCode
User1, ?
hashCodes
User2, ?
User2#hashCode
map.put(user1, 2); users.add(user1);

users.add(user2);
@blep#DevoxxFrEqHc
@Getter @Setter @ToString

private static class User{

private String name;



@Override

public boolean equals(Object obj) {

if (this == obj) return true;

if( ! (obj instanceof User) ) return false;



User other = (User) obj;



return this.name !=null ? this.name.equals(other.name) : this.name == other.name;

}



@Override

public int hashCode() {

return name == null? 0 : name.length(); // Ugly but correct!

}

}
hashCode
@blep#DevoxxFrEqHc
@Getter @Setter

private static class UserWithPassword extends User{

private String password;



@Override

public boolean equals(Object obj) {

if (this == obj) return true;

if(!super.equals(obj)) return false;



if( ! (obj instanceof UserWithPassword) ) return false;



UserWithPassword other = (UserWithPassword) obj;



return this.password !=null ?
this.password.equals(other.password) : this.password ==
other.password;

}



@Override

public int hashCode() {

return super.hashCode() + (password == null ? 0 :
password.length());

}

}



@Test

public void should_be_equals(){

final User user1 = new User();

user1.setName("bali");



final UserWithPassword user2 = new UserWithPassword();

user2.setName("bali");

user2.setPassword("balo");



/* Reflexive */

assertThat(user1.equals(user1)).isTrue();

assertThat(user2.equals(user2)).isTrue();

/* Symmetric */

assertThat(user1.equals(user2)).isTrue();

assertThat(user2.equals(user1)).isTrue(); // -> fails

}

@Test

public void hashCode_should_be_the_same(){

final User user1 = new User();

user1.setName("bali");



final UserWithPassword user2 = new UserWithPassword();

user2.setName("bali");

user2.setPassword("balo");



assertThat(user1.equals(user2)).isTrue();



/* contract with hashcode */

assertThat(user1.hashCode()).isEqualTo(user2.hashCode());
// --> fails

}
Le problème de l’héritage
Toujours aussi nulle
mon implémentation de
hashCode…
@blep#DevoxxFrEqHc
@Getter @Setter

private static class User{

private String name;



@Override

public boolean equals(Object obj) {

if (this == obj) return true;

if( ! (obj instanceof User) ) return false;



User other = (User) obj;



if(!other.canEqual(this)) return false;



return this.name !=null ?
this.name.equals(other.name) : this.name == other.name;

}



protected boolean canEqual(Object o) {

return o instanceof User;

}



@Override

public int hashCode() {

return name.length(); // Ugly but correct!

}

}




@Getter @Setter

private static class UserWithPassword extends User{

private String password;



@Override

public boolean equals(Object obj) {

if (this == obj) return true;

if(!super.equals(obj)) return false;



if( ! (obj instanceof UserWithPassword) ) return false;



UserWithPassword other = (UserWithPassword) obj;



if(!other.canEqual(this)) return false;



return this.password !=null ?
this.password.equals(other.password) : this.password ==
other.password;

}



@Override

protected boolean canEqual(Object o) {

return o instanceof UserWithPassword;

}



@Override

public int hashCode() {

return super.hashCode() + (password == null ? 0 :
password.length());

}

}
Le problème de l’héritage
@blep#DevoxxFrEqHc
Pour finir: comment bien faire?
• Pour une implémentation pertinente de hashCode: se référer à
l’item 9 de Effective Java (Josh Bloch)
• Plus facile : déléguer à Apache Commons Lang EqualsBuilder
et HashCodeBuilder
• Encore plus facile : demander à Lombok de les générer à votre
place
@blep#DevoxxFrEqHc
@Test

public void mutability_fails_in_collections(){

final User user = new User();

user.setName("bali");



final Set<User> set = new HashSet<>();

set.add(user);



assertThat(set).hasSize(1);

assertThat(set.contains(user)).isTrue();



user.setName("bali balo");



assertThat(set).hasSize(1);

assertThat(set.iterator().next()).isEqualTo(user);

assertThat(set.contains(user)).isTrue(); // --> fails



}

One more thing…

Contenu connexe

Tendances

EPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur PurnamaEPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
Enterprise PHP Center
 
The core libraries you always wanted - Google Guava
The core libraries you always wanted - Google GuavaThe core libraries you always wanted - Google Guava
The core libraries you always wanted - Google Guava
Mite Mitreski
 
Design Patterns in PHP5
Design Patterns in PHP5 Design Patterns in PHP5
Design Patterns in PHP5
Wildan Maulana
 
international PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secretsinternational PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secrets
smueller_sandsmedia
 

Tendances (20)

Google Guava for cleaner code
Google Guava for cleaner codeGoogle Guava for cleaner code
Google Guava for cleaner code
 
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur PurnamaEPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
 
The core libraries you always wanted - Google Guava
The core libraries you always wanted - Google GuavaThe core libraries you always wanted - Google Guava
The core libraries you always wanted - Google Guava
 
Ten useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesTen useful JavaScript tips & best practices
Ten useful JavaScript tips & best practices
 
Design Patterns in PHP5
Design Patterns in PHP5 Design Patterns in PHP5
Design Patterns in PHP5
 
international PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secretsinternational PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secrets
 
Functional Structures in PHP
Functional Structures in PHPFunctional Structures in PHP
Functional Structures in PHP
 
Google guava overview
Google guava overviewGoogle guava overview
Google guava overview
 
Chaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscoreChaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscore
 
Google guava - almost everything you need to know
Google guava - almost everything you need to knowGoogle guava - almost everything you need to know
Google guava - almost everything you need to know
 
JavaScript Fundamentals with Angular and Lodash
JavaScript Fundamentals with Angular and LodashJavaScript Fundamentals with Angular and Lodash
JavaScript Fundamentals with Angular and Lodash
 
Google Guava - Core libraries for Java & Android
Google Guava - Core libraries for Java & AndroidGoogle Guava - Core libraries for Java & Android
Google Guava - Core libraries for Java & Android
 
GPars (Groovy Parallel Systems)
GPars (Groovy Parallel Systems)GPars (Groovy Parallel Systems)
GPars (Groovy Parallel Systems)
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 
Java libraries you can't afford to miss
Java libraries you can't afford to missJava libraries you can't afford to miss
Java libraries you can't afford to miss
 
Advanced Debugging Using Java Bytecodes
Advanced Debugging Using Java BytecodesAdvanced Debugging Using Java Bytecodes
Advanced Debugging Using Java Bytecodes
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applications
 
Unit/Integration Testing using Spock
Unit/Integration Testing using SpockUnit/Integration Testing using Spock
Unit/Integration Testing using Spock
 
Java Concurrency by Example
Java Concurrency by ExampleJava Concurrency by Example
Java Concurrency by Example
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 

Similaire à Devoxx 15 equals hashcode

SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
jsmith92
 
SummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdf
SummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdfSummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdf
SummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdf
ARORACOCKERY2111
 
Scala in practice
Scala in practiceScala in practice
Scala in practice
patforna
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitinternational PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
smueller_sandsmedia
 
Object Oriented Programming with PHP 5 - More OOP
Object Oriented Programming with PHP 5 - More OOPObject Oriented Programming with PHP 5 - More OOP
Object Oriented Programming with PHP 5 - More OOP
Wildan Maulana
 
Introduction to CDI and DI in Java EE 6
Introduction to CDI and DI in Java EE 6Introduction to CDI and DI in Java EE 6
Introduction to CDI and DI in Java EE 6
Ray Ploski
 
PowerShell_LangRef_v3 (1).pdf
PowerShell_LangRef_v3 (1).pdfPowerShell_LangRef_v3 (1).pdf
PowerShell_LangRef_v3 (1).pdf
outcast96
 
JavaScript for PHP developers
JavaScript for PHP developersJavaScript for PHP developers
JavaScript for PHP developers
Stoyan Stefanov
 

Similaire à Devoxx 15 equals hashcode (20)

SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
 
SummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdf
SummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdfSummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdf
SummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdf
 
PHP Unit Testing
PHP Unit TestingPHP Unit Testing
PHP Unit Testing
 
Ejb3 Dan Hinojosa
Ejb3 Dan HinojosaEjb3 Dan Hinojosa
Ejb3 Dan Hinojosa
 
Scala in practice
Scala in practiceScala in practice
Scala in practice
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitinternational PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
 
Object Oriented Programming with PHP 5 - More OOP
Object Oriented Programming with PHP 5 - More OOPObject Oriented Programming with PHP 5 - More OOP
Object Oriented Programming with PHP 5 - More OOP
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 
Introduction to CDI and DI in Java EE 6
Introduction to CDI and DI in Java EE 6Introduction to CDI and DI in Java EE 6
Introduction to CDI and DI in Java EE 6
 
Test driven development_for_php
Test driven development_for_phpTest driven development_for_php
Test driven development_for_php
 
Java → kotlin: Tests Made Simple
Java → kotlin: Tests Made SimpleJava → kotlin: Tests Made Simple
Java → kotlin: Tests Made Simple
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl Techniques
 
Hack tutorial
Hack tutorialHack tutorial
Hack tutorial
 
PowerShell_LangRef_v3 (1).pdf
PowerShell_LangRef_v3 (1).pdfPowerShell_LangRef_v3 (1).pdf
PowerShell_LangRef_v3 (1).pdf
 
JavaScript for PHP developers
JavaScript for PHP developersJavaScript for PHP developers
JavaScript for PHP developers
 
Enterprise js pratices
Enterprise js praticesEnterprise js pratices
Enterprise js pratices
 
Everything is Permitted: Extending Built-ins
Everything is Permitted: Extending Built-insEverything is Permitted: Extending Built-ins
Everything is Permitted: Extending Built-ins
 
Objects, Testing, and Responsibility
Objects, Testing, and ResponsibilityObjects, Testing, and Responsibility
Objects, Testing, and Responsibility
 
Jsp presentation
Jsp presentationJsp presentation
Jsp presentation
 

Plus de bleporini

Perfug Guide de survie du développeur dans une application Java qui rame
Perfug Guide de survie du développeur dans une application Java qui ramePerfug Guide de survie du développeur dans une application Java qui rame
Perfug Guide de survie du développeur dans une application Java qui rame
bleporini
 

Plus de bleporini (6)

Kafka: Legacy microservices
Kafka: Legacy microservicesKafka: Legacy microservices
Kafka: Legacy microservices
 
Two way data sync between legacy and your brand new micro-service architecture
 Two way data sync between legacy and your brand new micro-service architecture Two way data sync between legacy and your brand new micro-service architecture
Two way data sync between legacy and your brand new micro-service architecture
 
Perfug Guide de survie du développeur dans une application Java qui rame
Perfug Guide de survie du développeur dans une application Java qui ramePerfug Guide de survie du développeur dans une application Java qui rame
Perfug Guide de survie du développeur dans une application Java qui rame
 
Breizhcamp : Guide de survie du développeur dans une application (Java) qui rame
Breizhcamp : Guide de survie du développeur dans une application (Java) qui rameBreizhcamp : Guide de survie du développeur dans une application (Java) qui rame
Breizhcamp : Guide de survie du développeur dans une application (Java) qui rame
 
Devoxx 15
Devoxx 15 Devoxx 15
Devoxx 15
 
JDBC / JPA / Hibernate: Sans maîtrise la puissance n’est rien!
JDBC / JPA / Hibernate: Sans maîtrise la puissance n’est rien!JDBC / JPA / Hibernate: Sans maîtrise la puissance n’est rien!
JDBC / JPA / Hibernate: Sans maîtrise la puissance n’est rien!
 

Dernier

Call Girls in Prashant Vihar, Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
Call Girls in Prashant Vihar, Delhi 💯 Call Us 🔝9953056974 🔝 Escort ServiceCall Girls in Prashant Vihar, Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
Call Girls in Prashant Vihar, Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
➥🔝 7737669865 🔝▻ mehsana Call-girls in Women Seeking Men 🔝mehsana🔝 Escorts...
➥🔝 7737669865 🔝▻ mehsana Call-girls in Women Seeking Men  🔝mehsana🔝   Escorts...➥🔝 7737669865 🔝▻ mehsana Call-girls in Women Seeking Men  🔝mehsana🔝   Escorts...
➥🔝 7737669865 🔝▻ mehsana Call-girls in Women Seeking Men 🔝mehsana🔝 Escorts...
nirzagarg
 
Thalassery Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call G...
Thalassery Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call G...Thalassery Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call G...
Thalassery Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call G...
Call Girls In Delhi Whatsup 9873940964 Enjoy Unlimited Pleasure
 
valsad Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call Girls...
valsad Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call Girls...valsad Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call Girls...
valsad Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call Girls...
Call Girls In Delhi Whatsup 9873940964 Enjoy Unlimited Pleasure
 
💚😋 Salem Escort Service Call Girls, 9352852248 ₹5000 To 25K With AC💚😋
💚😋 Salem Escort Service Call Girls, 9352852248 ₹5000 To 25K With AC💚😋💚😋 Salem Escort Service Call Girls, 9352852248 ₹5000 To 25K With AC💚😋
💚😋 Salem Escort Service Call Girls, 9352852248 ₹5000 To 25K With AC💚😋
nirzagarg
 

Dernier (20)

20240507 QFM013 Machine Intelligence Reading List April 2024.pdf
20240507 QFM013 Machine Intelligence Reading List April 2024.pdf20240507 QFM013 Machine Intelligence Reading List April 2024.pdf
20240507 QFM013 Machine Intelligence Reading List April 2024.pdf
 
Sarola * Female Escorts Service in Pune | 8005736733 Independent Escorts & Da...
Sarola * Female Escorts Service in Pune | 8005736733 Independent Escorts & Da...Sarola * Female Escorts Service in Pune | 8005736733 Independent Escorts & Da...
Sarola * Female Escorts Service in Pune | 8005736733 Independent Escorts & Da...
 
Call Girls in Prashant Vihar, Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
Call Girls in Prashant Vihar, Delhi 💯 Call Us 🔝9953056974 🔝 Escort ServiceCall Girls in Prashant Vihar, Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
Call Girls in Prashant Vihar, Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
 
Nanded City ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready ...
Nanded City ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready ...Nanded City ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready ...
Nanded City ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready ...
 
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
 
Trump Diapers Over Dems t shirts Sweatshirt
Trump Diapers Over Dems t shirts SweatshirtTrump Diapers Over Dems t shirts Sweatshirt
Trump Diapers Over Dems t shirts Sweatshirt
 
➥🔝 7737669865 🔝▻ mehsana Call-girls in Women Seeking Men 🔝mehsana🔝 Escorts...
➥🔝 7737669865 🔝▻ mehsana Call-girls in Women Seeking Men  🔝mehsana🔝   Escorts...➥🔝 7737669865 🔝▻ mehsana Call-girls in Women Seeking Men  🔝mehsana🔝   Escorts...
➥🔝 7737669865 🔝▻ mehsana Call-girls in Women Seeking Men 🔝mehsana🔝 Escorts...
 
Pune Airport ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready...
Pune Airport ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready...Pune Airport ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready...
Pune Airport ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready...
 
Real Men Wear Diapers T Shirts sweatshirt
Real Men Wear Diapers T Shirts sweatshirtReal Men Wear Diapers T Shirts sweatshirt
Real Men Wear Diapers T Shirts sweatshirt
 
Call Girls Sangvi Call Me 7737669865 Budget Friendly No Advance BookingCall G...
Call Girls Sangvi Call Me 7737669865 Budget Friendly No Advance BookingCall G...Call Girls Sangvi Call Me 7737669865 Budget Friendly No Advance BookingCall G...
Call Girls Sangvi Call Me 7737669865 Budget Friendly No Advance BookingCall G...
 
Thalassery Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call G...
Thalassery Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call G...Thalassery Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call G...
Thalassery Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call G...
 
VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting High Prof...
VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting  High Prof...VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting  High Prof...
VIP Model Call Girls Hadapsar ( Pune ) Call ON 9905417584 Starting High Prof...
 
Russian Call Girls Pune (Adult Only) 8005736733 Escort Service 24x7 Cash Pay...
Russian Call Girls Pune  (Adult Only) 8005736733 Escort Service 24x7 Cash Pay...Russian Call Girls Pune  (Adult Only) 8005736733 Escort Service 24x7 Cash Pay...
Russian Call Girls Pune (Adult Only) 8005736733 Escort Service 24x7 Cash Pay...
 
Hire↠Young Call Girls in Tilak nagar (Delhi) ☎️ 9205541914 ☎️ Independent Esc...
Hire↠Young Call Girls in Tilak nagar (Delhi) ☎️ 9205541914 ☎️ Independent Esc...Hire↠Young Call Girls in Tilak nagar (Delhi) ☎️ 9205541914 ☎️ Independent Esc...
Hire↠Young Call Girls in Tilak nagar (Delhi) ☎️ 9205541914 ☎️ Independent Esc...
 
"Boost Your Digital Presence: Partner with a Leading SEO Agency"
"Boost Your Digital Presence: Partner with a Leading SEO Agency""Boost Your Digital Presence: Partner with a Leading SEO Agency"
"Boost Your Digital Presence: Partner with a Leading SEO Agency"
 
valsad Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call Girls...
valsad Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call Girls...valsad Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call Girls...
valsad Escorts Service ☎️ 6378878445 ( Sakshi Sinha ) High Profile Call Girls...
 
20240509 QFM015 Engineering Leadership Reading List April 2024.pdf
20240509 QFM015 Engineering Leadership Reading List April 2024.pdf20240509 QFM015 Engineering Leadership Reading List April 2024.pdf
20240509 QFM015 Engineering Leadership Reading List April 2024.pdf
 
APNIC Updates presented by Paul Wilson at ARIN 53
APNIC Updates presented by Paul Wilson at ARIN 53APNIC Updates presented by Paul Wilson at ARIN 53
APNIC Updates presented by Paul Wilson at ARIN 53
 
💚😋 Salem Escort Service Call Girls, 9352852248 ₹5000 To 25K With AC💚😋
💚😋 Salem Escort Service Call Girls, 9352852248 ₹5000 To 25K With AC💚😋💚😋 Salem Escort Service Call Girls, 9352852248 ₹5000 To 25K With AC💚😋
💚😋 Salem Escort Service Call Girls, 9352852248 ₹5000 To 25K With AC💚😋
 
2nd Solid Symposium: Solid Pods vs Personal Knowledge Graphs
2nd Solid Symposium: Solid Pods vs Personal Knowledge Graphs2nd Solid Symposium: Solid Pods vs Personal Knowledge Graphs
2nd Solid Symposium: Solid Pods vs Personal Knowledge Graphs
 

Devoxx 15 equals hashcode

  • 1. @blep#DevoxxFrEqHc RÉVISION DES FONDAMENTAUX : EQUALS ET HASHCODE C'EST IMPORTANT Brice LEPORINI @blep Indépendant http://the-babel-tower.github.io/
  • 2. @blep#DevoxxFrEqHc Pourquoi? •Les devs sont rarement affûtés sur cette problématique •La plupart des implémentations sont buggées
  • 3. @blep#DevoxxFrEqHc L’opérateur == •Permet de comparer des types primitifs •Utiliser == sur les objets ne permet que de vérifier que deux références pointent sur la même instance
  • 5. @blep#DevoxxFrEqHc @Getter @Setter
 private static class User{
 private String name;
 }
 
 
 @Test
 public void testEquals() {
 final User user1 = new User();
 user1.setName("test");
 
 final User user2 = new User();
 user2.setName("test");
 
 assertThat(user1.equals(user1)).isTrue(); //Reflexive
 assertThat(user2.equals(user2)).isTrue(); //Reflexive
 
 assertThat(user1.equals(null)).isFalse();
 
 assertThat(user1.equals(user2)).isTrue(); // —> Fails
 
 }
 java.lang.Object#equals
  • 6. @blep#DevoxxFrEqHc Redéfinir equals • Seul moyen de vérifier que deux instances distinctes sont fonctionnellement équivalentes
  • 7. @blep#DevoxxFrEqHc @Getter @Setter @ToString
 private static class User{
 private String name;
 
 @Override
 public boolean equals(Object obj) {
 if (this == obj) return true;
 if( ! (obj instanceof User) ) return false;
 
 User other = (User) obj;
 
 return this.name !=null ? this.name.equals(other.name) : this.name == other.name;
 }
 }
 @Test
 public void should_be_equals() {
 final User user1 = new User();
 user1.setName("bali");
 
 final User user2 = new User();
 user2.setName("bali");
 
 final User user3 = new User();
 user3.setName("bali");
 
 /* Reflexive */
 assertThat(user1.equals(user1)).isTrue();
 assertThat(user2.equals(user2)).isTrue();
 assertThat(user3.equals(user3)).isTrue();
 
 /* Symmetric */
 assertThat(user1.equals(user2)).isTrue();
 assertThat(user2.equals(user1)).isTrue();
 
 /* Transitive */
 assertThat(user2.equals(user3)).isTrue();
 assertThat(user1.equals(user3)).isTrue();
 
 assertThat(user1.equals(null)).isFalse();
 assertThat(user2.equals(null)).isFalse();
 assertThat(user3.equals(null)).isFalse();
 } Redéfinir equals
  • 8. @blep#DevoxxFrEqHc @Test
 public void testHashMap() {
 final User user1 = new User();
 user1.setName("bali");
 
 final User user2 = new User();
 user2.setName("bali");
 
 final Map<User, Integer> map = new HashMap<>();
 map.put(user1, 2);
 
 assertThat(map).hasSize(1);
 assertThat(map.keySet().iterator().next()).isEqualTo(user2);
 assertThat(map.values().iterator().next()).isEqualTo(2);
 assertThat(map).containsEntry(user2, 2); // —> fails
 }
 @Test
 public void testHashSet() {
 final User user1 = new User();
 user1.setName("bali");
 
 final User user2 = new User();
 user2.setName("bali");
 
 final Set<User> users = new HashSet<>();
 users.add(user1);
 
 assertThat(users.iterator().next()).isEqualTo(user2);
 assertThat(users.contains(user2)).isTrue(); // -> fails
 }
 @Test
 public void should_not_contain_doubles() {
 final User user1 = new User();
 user1.setName("bali");
 
 final User user2 = new User();
 user2.setName("bali");
 
 final Set<User> users = new HashSet<>();
 users.add(user1);
 users.add(user2);
 
 assertThat(user1.equals(user2)).isTrue();
 assertThat(users).hasSize(1); // —> fails
 
 }
 Généralement —> systématiquement java.lang.AssertionError: Expecting: <{_01BasicEquals.User(name=bali)=2}> to contain: <[MapEntry[key=_01BasicEquals.User(name=bali), value=2]]> but could not find: <[MapEntry[key=_01BasicEquals.User(name=bali), value=2]]>
  • 9. @blep#DevoxxFrEqHc HashCode • Valeur entière représentant la réduction d’un objet
  • 10. @blep#DevoxxFrEqHc Hash CollectionsUser1#hashCode User1, 2 hashCodes User1#hashCode User1, ? hashCodes User2, ? User2#hashCode map.put(user1, 2); users.add(user1);
 users.add(user2);
  • 11. @blep#DevoxxFrEqHc @Getter @Setter @ToString
 private static class User{
 private String name;
 
 @Override
 public boolean equals(Object obj) {
 if (this == obj) return true;
 if( ! (obj instanceof User) ) return false;
 
 User other = (User) obj;
 
 return this.name !=null ? this.name.equals(other.name) : this.name == other.name;
 }
 
 @Override
 public int hashCode() {
 return name == null? 0 : name.length(); // Ugly but correct!
 }
 } hashCode
  • 12. @blep#DevoxxFrEqHc @Getter @Setter
 private static class UserWithPassword extends User{
 private String password;
 
 @Override
 public boolean equals(Object obj) {
 if (this == obj) return true;
 if(!super.equals(obj)) return false;
 
 if( ! (obj instanceof UserWithPassword) ) return false;
 
 UserWithPassword other = (UserWithPassword) obj;
 
 return this.password !=null ? this.password.equals(other.password) : this.password == other.password;
 }
 
 @Override
 public int hashCode() {
 return super.hashCode() + (password == null ? 0 : password.length());
 }
 }
 
 @Test
 public void should_be_equals(){
 final User user1 = new User();
 user1.setName("bali");
 
 final UserWithPassword user2 = new UserWithPassword();
 user2.setName("bali");
 user2.setPassword("balo");
 
 /* Reflexive */
 assertThat(user1.equals(user1)).isTrue();
 assertThat(user2.equals(user2)).isTrue();
 /* Symmetric */
 assertThat(user1.equals(user2)).isTrue();
 assertThat(user2.equals(user1)).isTrue(); // -> fails
 }
 @Test
 public void hashCode_should_be_the_same(){
 final User user1 = new User();
 user1.setName("bali");
 
 final UserWithPassword user2 = new UserWithPassword();
 user2.setName("bali");
 user2.setPassword("balo");
 
 assertThat(user1.equals(user2)).isTrue();
 
 /* contract with hashcode */
 assertThat(user1.hashCode()).isEqualTo(user2.hashCode()); // --> fails
 } Le problème de l’héritage Toujours aussi nulle mon implémentation de hashCode…
  • 13. @blep#DevoxxFrEqHc @Getter @Setter
 private static class User{
 private String name;
 
 @Override
 public boolean equals(Object obj) {
 if (this == obj) return true;
 if( ! (obj instanceof User) ) return false;
 
 User other = (User) obj;
 
 if(!other.canEqual(this)) return false;
 
 return this.name !=null ? this.name.equals(other.name) : this.name == other.name;
 }
 
 protected boolean canEqual(Object o) {
 return o instanceof User;
 }
 
 @Override
 public int hashCode() {
 return name.length(); // Ugly but correct!
 }
 } 
 
 @Getter @Setter
 private static class UserWithPassword extends User{
 private String password;
 
 @Override
 public boolean equals(Object obj) {
 if (this == obj) return true;
 if(!super.equals(obj)) return false;
 
 if( ! (obj instanceof UserWithPassword) ) return false;
 
 UserWithPassword other = (UserWithPassword) obj;
 
 if(!other.canEqual(this)) return false;
 
 return this.password !=null ? this.password.equals(other.password) : this.password == other.password;
 }
 
 @Override
 protected boolean canEqual(Object o) {
 return o instanceof UserWithPassword;
 }
 
 @Override
 public int hashCode() {
 return super.hashCode() + (password == null ? 0 : password.length());
 }
 } Le problème de l’héritage
  • 14. @blep#DevoxxFrEqHc Pour finir: comment bien faire? • Pour une implémentation pertinente de hashCode: se référer à l’item 9 de Effective Java (Josh Bloch) • Plus facile : déléguer à Apache Commons Lang EqualsBuilder et HashCodeBuilder • Encore plus facile : demander à Lombok de les générer à votre place
  • 15. @blep#DevoxxFrEqHc @Test
 public void mutability_fails_in_collections(){
 final User user = new User();
 user.setName("bali");
 
 final Set<User> set = new HashSet<>();
 set.add(user);
 
 assertThat(set).hasSize(1);
 assertThat(set.contains(user)).isTrue();
 
 user.setName("bali balo");
 
 assertThat(set).hasSize(1);
 assertThat(set.iterator().next()).isEqualTo(user);
 assertThat(set.contains(user)).isTrue(); // --> fails
 
 }
 One more thing…