Première étape de ma cure de rattrapage Java : repartir des bases de Java 6. Pour cela, j’avais déjà ce qu’il me fallait dans ma bibliothèque: Effective Java, Second Edition de Joshua Bloch que j’avais lu il y a quelques années.

Joshua Bloch est un développeur reconnu, il a notamment travaillé chez Sun Microsystems et Google et il a dirigé plusieurs spécifications et implémentations Java dont la fameuse Java Collections.

Effective Java est une mine de bonnes pratiques, basée sur l’expérience de son auteur pour écrire du code Java efficient, notamment lorsque l’on développe une bibliothèque dont l’API sera fortement exposée.
La seconde édition a été mise à jour pour Java 6, ce qui peut-être paraître un peu daté à l’heure de Java 8. Mais, même si quelques items ne sont plus forcément d’actualité avec l’avènement des nouvelles versions de Java (ex: concurrence), la majorité des conseils sont bons à prendre car ils ne sont pas liés au langage lui-même mais à la programmation objet en général.

Le livre est découpé en 78 items répartis en 10 parties, que je vais reprendre ici, en condensé, afin de servir de mémo.

Partie 1 - Création et suppression d’objets
    - Item 1 - Envisager les méthodes statiques de fabrique plutôt que les constructeurs
    - Item 2 - Envisager un “builder” face à un constructeur à beaucoup de paramètres
    - Item 3 - Renforcer la propriété de singleton par un constructeur privé ou un enum
    - Item 4 - Renforcer la “non-instantiation” par un constructeur privé
    - Item 5 - Éviter de créer des objets inutilement
    - Item 6 - Éliminer les références vers les objets obsolètes
    - Item 7 - Éviter les “finalizers”
Partie 2 - Méthodes communes à tous les objets Java
    - Item 8 - Respecter le contrat généralement admis lors de la redéfinition de equals
    - Item 9 - Toujours redéfinir hashcode lorsque equals est redéfinie
    - Item 10 - Toujours redéfinir toString
    - Item 11 - Redéfinir clone de façon judicieuse
    - Item 12 - Envisager d’implémenter Comparable
Partie 3 - Classes et interfaces
    - Item 13 - Minimiser l’accessibilité des classes et des membres
    - Item 14 - Utiliser des accesseurs plutôt que des attributs publics
    - Item 15 - Maximiser l’immuabilité (i.e. instances non modifiables)
    - Item 16 - Favoriser la composition plutôt que l’héritage
    - Item 17 - Concevoir et documenter en vue de l’héritage ou alors l’interdire
    - Item 18 - Favoriser les interfaces plutôt que les classes abstraites
    - Item 19 - N’utiliser les interfaces que pour définir des types
    - Item 20 - Favoriser des hiérarchie de classe plutôt que des classes “tagées”
    - Item 21 - Utiliser des objets fonctions pour représenter des stratégies
    - Item 22 - Favoriser les classes internes statiques plutôt que non statiques
Partie 4 - Génériques
    - Item 23 - Ne plus utiliser les “raw types” (i.e. container non générique)
    - Item 24 - Éliminer les “unchecked warnings”
    - Item 25 - Favoriser les listes aux tableaux
    - Item 26 - Favoriser les types génériques
    - Item 27 - Favoriser les méthodes génériques
    - Item 28 - Utiliser les “bounded wildcards” dans les paramètres de méthodes (ex: Iterable<? extends E> plutôt que Iterable<E>)
    - Item 29 - Envisager les “typesafe heterogeneous containers”
Partie 5 - Enums et annotations
    - Item 30 - Utiliser des enums plutôt que des int
    - Item 31 - Utiliser des instances d’enums plutôt que leur ordinal
    - Item 32 - Utiliser des EnumSet plutôt que des “bit fields” (notamment pour les “flags”)
    - Item 33 - Utiliser des EnumMap plutôt qu’une indexation par ordinal d’enum
    - Item 34 - Simuler des enums étendus avec des interfaces
    - Item 35 - Préférer les annotations à l’utilisation de chaînes de caractères(“naming patterns”)
    - Item 36 - Toujours utiliser l’annotation @Override lors d’une redéfinition
    - Item 37 - Utiliser des interfaces “marker” pour définir des types (des interfaces sans méthode comme Serializable)
Partie 6 - Méthodes
    - Item 38 - Vérifier la validité des paramètres
    - Item 39 - Faire des copies défensives quand nécessaire
    - Item 40 - Bien réfléchir aux signatures de méthodes (surtout quand elles font parties de l’API)
    - Item 41 - Utiliser la surcharge de façon judicieuse
    - Item 42 - Utiliser les varargs de façon judicieuse
    - Item 43 - Retourner des containers ou tableaux vides plutôt que des objets null
    - Item 44 - Écrire des commentaires de documentation pour les méthodes de l’API
Partie 7 - Programmation générale
    - Item 45 - Minimiser la portée des variables locales
    - Item 46 - Favoriser les boucles for-each plutôt que les boucles “classiques”
    - Item 47 - Connaître et utiliser les bibliothèques classiques
    - Item 48 - Éviter les float et les double si des réponses exactes sont nécessaires (utiliser notamment BigDecimal)
    - Item 49 - Préférer les types primitifs aux équivalents “boxes” lors de traitement (=> évite les copies coûteuses)
    - Item 50 - Éviter les chaînes de caractères lorsqu’un type plus approprié existe
    - Item 51 - Être attentif à la performance de la concaténation de chaînes de caractères (utiliser des StringBuilder)
    - Item 52 - Faire référence à des objets par leurs interfaces (plutôt que par leur implémentations, ex: List et ArrayList)
    - Item 53 - Préférer les interfaces aux mécanismes de réflexion
    - Item 54 - Utiliser les méthodes “natives” de façon judicieuse
    - Item 55 - Optimiser de façon judicieuse
    - Item 56 - Adhérer aux conventions de nommage généralement admises (surtout pour le développement de bibliothèques)
Partie 8 - Exceptions
    - Item 57 - Utiliser les exceptions uniquement pour les événements exceptionnels
    - Item 58 - Utiliser les “checked exceptions” pour les situations rattrapables et les “runtime exceptions” pour les erreurs de programmation
    - Item 59 - Éviter l’utilisation inutile de “checked exceptions”
    - Item 60 - Préférer la réutilisation d’exceptions standards
    - Item 61 - Renvoyer des exceptions appropriées au niveau d’abstraction courant
    - Item 62 - Documenter toutes les exceptions envoyées par chaque méthode
    - Item 63 - Inclure des informations/données sur l’incident dans les détails d’une exception
    - Item 64 - Favoriser l’atomicité de l’échec (i.e. envoyer les exceptions au plus tôt, notamment avant de créer des objets)
    - Item 65 - Ne pas ignorer les exceptions
Partie 9 - Concurrence
    - Item 66 - Synchroniser l’accès aux données partagées
    - Item 67 - Éviter les synchronisations excessives
    - Item 68 - Favoriser les “executors” et les “tasks” aux threads
    - Item 69 - Favoriser l’utilisation des classes de concurrence utilitaires plutôt que wait et notify
    - Item 70 - Documenter le niveau de “thread safety”
    - Item 71 - Utiliser l’initialisation paresseuse(“lazy”) de façon judicieuse
    - Item 72 - Ne pas dépendre de l’ordonnanceur de thread (“thread scheduler”)
    - Item 73 - Éviter les groupes de threads (la ThreadGroup API est obsolète)
Partie 10 - Sérialisation
    - Item 74 - Implémenter Serializable de façon judicieuse
    - Item 75 - Envisager l’utilisation d’une forme de sérialisation “custom”
    - Item 76 - Écrire la méthode readObject de façon défensive
    - Item 77 - Pour assurer le contrôle de l’instantiation, préférer les singletons à readResolve
    - Item 78 - Envisager d’utiliser un “proxy” de sérialisation plutôt que la sérialisation des instances