Dans la programmation Java, certaines connaissances ne peuvent être apprises que par les spécifications du langage ou la documentation API standard. Dans cet article, j'essaierai de collecter certains des idiomes les plus couramment utilisés, en particulier ceux qui sont difficiles à deviner.
J'ai mis tout le code dans cet article dans les lieux publics. Vous pouvez copier et modifier n'importe quel extrait de code en fonction de vos préférences, sans aucune information.
Implémenter equals ()
classe de classe {String name; int anniversaireyear; octet [] brut; Le booléen public est égal (objet obj) {if (! obj instanceof personne) renvoie false; Personne autre = (personne) obj; retour name.equals (autre.name) && anniversaireyear == autre.birthyear && arrays.equals (brut, autre.raw); } public int hashcode () {...}} Le paramètre doit être de type objet, pas d'une classe périphérique.
foo.equals (null) doit retourner false et ne peut pas lancer nullpointerException. (Notez que l'instance nulle de n'importe quelle classe renvoie toujours false, de sorte que le code ci-dessus peut être exécuté.)
La comparaison des domaines de type de base (par exemple, INT) est utilisée ==, et la comparaison des domaines de tableau de type de base est utilisée par Arrays.equals ().
Lorsque vous écrasez Equals (), n'oubliez pas d'écraser HashCode () en conséquence, pour être cohérent avec equals ().
Référence: java.lang.object.equals (objet).
Implémenter HashCode ()
classe de classe {String a; Objet B; octet C; int [] d; public int hashcode () {return a.hashcode () + b.hashcode () + c + arrays.hashcode (d); } public booléen égaux (objet O) {...}} Lorsque les objets x et y ont x.equals (y) == true, vous devez vous assurer que x.hashcode () == y.hashcode ().
Selon la proposition inverse, si x.hashcode ()! = Y.hashcode (), alors x.equals (y) == false doit être vrai.
Vous n'avez pas besoin de garantir que x.hashcode ()! = Y.hashcode () Quand x.equals (y) == false. Cependant, cela améliore les performances de la table de hachage si vous pouvez le faire le plus longtemps possible.
La mise en œuvre légale la plus simple de HashCode () est simplement de retourner 0; Bien que cette implémentation soit correcte, cela entraînera l'exécution très lentement des structures de données telles que HashMap.
Implémenter compareto ()
La personne de classe implémente comparable <ponse> {String FirstName; String LastName; int anniversaire; // Comparez par FirstName, Break Ties by LastName, enfin Break Ties by Birthdate public int compareto (personne autre) {if (FirstName ..comPareto (autre.FirstName)! = 0) return FirstName ..Careto (autre.FirstName); else if (lastName.compareto (other.lastName)! = 0) return lastName ..........mardName.compareto (autre.lastName); else if (naissance <autre.birthdate) retour -1; else if (naissance> autre.birthdate) retour 1; else return 0; }} Implémentez toujours la version générique comparable au lieu de type primitif comparable. Parce que cela peut économiser le volume de code et réduire les tracas inutiles.
Il suffit de se soucier des signes (négatifs / zéro / positifs) qui renvoient le résultat, leur taille n'a pas d'importance.
La mise en œuvre de comparateur.compare () est similaire à celle-ci.
Implémenter clone ()
Les valeurs de classe implémentent clonables {String ABC; double foo; bars int []; Date embauchée; VALEURS PUBLIC CLONE () {try {valeurs result = (valeurs) super.clone (); result.bars = result.bars.clone (); result.hired = result.hired.clone (); Résultat de retour; } catch (clonenotsupportEdException e) {// Impossible Throw New AssertionError (e); }}} Utilisez super.clone () pour rendre la classe d'objets responsable de la création de nouveaux objets.
Les domaines de type de base ont été copiés correctement. Encore une fois, nous n'avons pas besoin de cloner des types immuables comme String et BigInteger.
Effectuez manuellement la copie profonde de tous les champs de types non primitifs (objets et tableaux).
La classe clonable est mise en œuvre et la méthode Clone () ne doit jamais lancer de clonenotsupportedException. Par conséquent, vous devez attraper cette exception et l'ignorer, ou l'envelopper avec une exception non contrôlée.
Il est correct et légal d'implémenter manuellement la méthode clone () sans utiliser la méthode object.clone ().
Utiliser StringBuilder ou StringBuffer
// join (["a", "b", "c"]) -> "a et b et c" string join (list <string> strs) {StringBuilder sb = new StringBuilder (); booléen d'abord = true; for (String s: strs) {if (first) first = false; else sb.append ("et"); SB.APPEND (S); } return sb.toString ();} N'utilisez pas la concaténation en double de la chaîne comme ceci: s + = élément, car son efficacité de temps est o (n ^ 2).
Lorsque vous utilisez StringBuilder ou StringBuffer, vous pouvez utiliser la méthode APPEND () pour ajouter du texte et utiliser la méthode ToString () pour obtenir le texte entier connecté.
La priorité est donnée à StringBuilder car elle est plus rapide. Toutes les méthodes de StringBuffer sont synchronisées et vous n'avez généralement pas besoin d'une méthode synchronisée.
Générer des entiers aléatoires dans une gamme
Random rand = new random (); // entre 1 et 6, y compris diceroll () {return rand.nextint (6) + 1;} Utilisez toujours la méthode de l'API Java pour générer un nombre aléatoire dans la gamme des entiers.
N'essayez pas d'utiliser math.abs (rand.nextint ())% n pour ces utilisations incertaines, car ses résultats sont biaisés. De plus, sa valeur de résultat peut être négative, comme lorsque rand.nextint () == Integer.min_value.
Utilisez iterator.remove ()
void filter (list <string> list) {for (iterator <string> iter = list.iterator (); iter.hasnext ();) {string item = iter.next (); if (...) iter.remove (); }}La méthode supprimée () agit sur l'entrée récemment retournée de la méthode suivante (). Chaque entrée ne peut utiliser la méthode Suppor () qu'une seule fois.
Chaîne de retour
String Reverse (String S) {return new StringBuilder (S) .Reverse (). ToString ();}Cette méthode devrait probablement être ajoutée à la bibliothèque Java Standard.
Démarrer un fil
Les trois exemples suivants font la même chose de différentes manières.
Comment implémenter Runnnable:
void startAthread0 () {nouveau thread (new myrunnable ()). start ();} class myrunnable implémente runnable {public void run () {...}}Comment hériter du fil:
void startAtHread1 () {new myThread (). start ();} class Mythread étend Thread {public void run () {...}}Comment hériter du fil de manière anonyme:
void startAtHread2 () {new Thread () {public void run () {...}} .start ();}N'appelez pas directement la méthode run (). La méthode thread.start () est toujours appelée, ce qui crée un nouveau thread et provoque l'appel de fil nouvellement créé ().
Utilisez TRY-FINALABLE
Exemple de flux d'E / S:
void WriteStuff () lève ioException {OutputStream out = new FileOutputStream (...); essayez {out.write (...); } enfin {out.close (); }}Exemple de verrouillage:
void dowithlock (Lock Lock) {lock.acquire (); essayez {...} enfin {lock.release (); }} Si l'instruction avant l'essai ne parvient pas à s'exécuter et qu'une exception est lancée, le bloc de l'instruction final ne sera pas exécuté. Mais quoi qu'il arrive, dans cet exemple, il n'est pas nécessaire de s'inquiéter de la publication des ressources.
Si l'instruction dans l'instruction TRYS lance une exception, l'exécution du programme sautera vers le bloc de l'instruction finalement pour exécuter autant d'instructions que possible, puis sauter de cette méthode (à moins que cette méthode ait un autre bloc d'instructions périphérique).
Lire les données des octets à partir du flux d'entrée
InputStream in = (...); try {while (true) {int b = in.read (); if (b == -1) casser; (... processus b ...)}} enfin {in.close ();}La méthode read () renvoie le numéro suivant d'octets lus dans le flux (0 à 255, y compris 0 et 255), ou renvoie -1 lorsque la fin du flux est atteinte.
Lire les données du bloc du flux d'entrée
InputStream dans = (...); try {byte [] buf = new octet [100]; while (true) {int n = in.read (buf); if (n == -1) casser; (... processus buf avec offset = 0 et longueur = n ...)}} enfin {in.close ();}N'oubliez pas que la méthode read () ne remplit pas nécessairement le BUF entier, vous devez donc considérer la durée du retour dans la logique de traitement.
Lire le texte à partir d'un fichier
BufferedReader dans = new BufferedReader (new InputStreamReader (new FileInputStream (...), "utf-8")); try {while (true) {String line = in.readline (); if (line == null) casser; (... Ligne de processus ...)}} Enfin {in.close ();} La création de l'objet BufferedReader semble très verbeux. En effet, Java traite les octets et les personnages comme deux concepts différents (c'est différent de C).
Vous pouvez utiliser n'importe quel type de SpointStream au lieu de FileInputStream, tel que Socket.
BufferedReader.Readline () renvoie NULL lorsque la fin du flux est atteinte.
Pour lire un caractère à la fois, utilisez la méthode Reader.read ().
Vous pouvez utiliser d'autres encodages de caractères sans UTF-8, mais il vaut mieux ne pas le faire.
Écrire du texte dans un fichier
Printwriter out = new printwriter (new OutputStreamWriter (new FileOutputStream (...), "utf-8")); try {out.print ("Bonjour"); Out.print (42); out.println ("world!");} enfin {out.close ();} La création d'objets Printwriter semble être très verbeux. En effet, Java traite les octets et les personnages comme deux concepts différents (c'est différent de C).
Tout comme System.out, vous pouvez utiliser print () et println () pour imprimer plusieurs types de valeurs.
Vous pouvez utiliser d'autres encodages de caractères sans UTF-8, mais il vaut mieux ne pas le faire.
Valeur de vérification défensive
int factorial (int n) {if (n <0) lance un nouveau IllégalArgumentException ("Undefined"); else if (n> = 13) lance un nouveau arithmeticexception ("Résultat débordement"); else if (n == 0) return 1; else return n * factorial (n - 1);} Ne pensez pas que les valeurs d'entrée sont positives, suffisamment petites, etc. pour détecter ces conditions explicitement.
Une fonction bien conçue devrait être en mesure d'exécuter correctement pour toutes les valeurs d'entrée possibles. Assurez-vous que toutes les situations sont prises en compte et qu'il n'y a pas de mauvaise sortie (comme le débordement).
Objets de test préventif
int findIndex (list <string> list, string target) {if (list == null || cible == null) lancez new nullpointerException (); ...}Ne pensez pas que les paramètres d'objet ne seront pas nuls. Pour détecter explicitement cette condition.
Index du tableau de détection préventive
void frob (byte [] b, int index) {if (b == null) lance un nouveau nullpointerException (); if (index <0 || index> = b.length) lancez un nouvel indexoutofboundSexception (); ...}Ne pensez pas que l'indice de tableau donné ne traversera pas les limites. Pour le détecter explicitement.
Intervalle de réseau de détection préventive
void frob (byte [] b, int off, int len) {if (b == null) lance un nouveau nullpointerException (); if (off <0 || off> b.length || len <0 || b.length - off <len) lancez la nouvelle indexoutofboundSexception (); ...}Ne pensez pas que l'intervalle de tableau donné (par exemple, à partir des éléments de lecture de Len) n'ira pas au-delà des limites. Pour le détecter explicitement.
Remplissez les éléments du tableau
Utilisation de boucles:
// Remplissez chaque élément du tableau 'a' avec 123 byte [] a = (...); pour (int i = 0; i <a.Length; i ++) a [i] = 123;
(Préférentiel) Méthodes pour utiliser la bibliothèque standard:
Arrays.filt (A, (octet) 123);
Copiez un élément de tableau dans une gamme
Utilisation de boucles:
// Copier 8 éléments du tableau 'A' commençant par décalage 3 // à Array 'B' commençant par décalage 6, // en supposant 'a' et 'b' sont des arraysyte distincts [] a = (...); octet [] b = (...); pour (int i = 0; i <8; i ++) b [6 + i] = a [3 + i];
(Préférentiel) Méthodes pour utiliser la bibliothèque standard:
System.ArrayCopy (A, 3, B, 6, 8);
Redimensionner le tableau
Utilisez des boucles (mise à l'échelle):
// faire un array 'a' plus grand pour newlenbyte [] a = (...); byte [] b = new byte [newlen]; for (int i = 0; i <a.length; i ++) // monte jusqu'à la longueur de a b [i] = a [i]; a = b;
Utilisez des boucles (réduisez la taille):
// faire un array 'a' plus petit à newlenbyte [] a = (...); byte [] b = new byte [newlen]; for (int i = 0; i <b.length; i ++) // monte jusqu'à la longueur de b b [i] = a [i]; a = b;
(Préférentiel) Méthodes pour utiliser la bibliothèque standard:
a = arrays.copyof (a, newlen);
Emballage 4 octets dans un int
int packBigendien (byte [] b) {return (b [0] & 0xff) << 24 | (b [1] & 0xff) << 16 | (b [2] & 0xff) << 8 | (b [3] & 0xff) << 0;} int packlittleendian (byte [] b) {return (b [0] & 0xff) << 0 | (b [1] & 0xff) << 8 | (b [2] & 0xff) << 16 | (b [3] & 0xff) << 24;}Décomposer int en 4 octets
[] UnmackBigeNian (int x) {return new octet [] {(octet) (x >>> 24), (octet) (x >>> 16), (octet) (x >>> 8), (octet) (x >>> 0)};} Byte [] unmacklittleendian (int x) {return byte [] {(byte) (x >> 0), 0) (octet) (x >>> 8), (octet) (x >>> 16), (octet) (x >>> 24)};}Utilisez toujours l'opérateur de shift à droite non signé (>>>) pour envelopper les bits, n'utilisez pas l'opérateur de shift à droite arithmétique (>>).