Préface
Je l'ai révisé en mars 2016 et j'ai revu pourquoi je dois optimiser le code en fonction de mon propre travail et de mon expérience d'apprentissage quotidienne. Avant de modifier, ma déclaration était comme ceci:
Tout comme une baleine mangeant des crevettes, peut-être que manger une ou deux crevettes n'est pas très efficace pour les baleines, mais si vous mangez trop de crevettes, les baleines seront naturellement pleines. L'optimisation du code est la même. Peut-être qu'une ou deux optimisations sont peu importantes pour améliorer l'efficacité du code, mais tant que vous pouvez prêter attention à l'optimisation du code partout, il est généralement très utile pour améliorer l'efficacité du code du code.
Cette vue, dans la vue actuelle, est une raison de l'optimisation du code, mais elle n'est pas complètement correcte. Aujourd'hui, avec le développement de la technologie mécanique, les serveurs ont souvent 8 cœurs, 16 cœurs et des processeurs 64 bits, et l'efficacité d'exécution du code est très élevée. StringBuilder remplace StringBuffer et ArrayList remplace Vector, ce qui améliore l'efficacité de l'opération de code par minuscule. Même si vous remarquez chaque point du projet, vous ne pouvez pas voir de modifications évidentes dans l'opération de code.
Je pense que le rôle le plus important de l'optimisation du code devrait être: éviter les erreurs inconnues. Pendant le code exécuté en ligne, de nombreuses erreurs inattendues se produisent souvent, car l'environnement en ligne et l'environnement de développement sont très différents, et le positionnement des erreurs est souvent une très petite raison. Cependant, afin de résoudre cette erreur, nous devons d'abord s'auto-vérifier, puis emballer le fichier de classe à remplacer, suspendre l'entreprise et redémarrer. Pour un projet mature, le dernier a en fait un très grand impact, ce qui signifie que les utilisateurs ne peuvent pas accéder à l'application au cours de cette période. Par conséquent, lors de l'écriture de code, prêter attention à divers détails de la source, peser et utiliser les meilleurs choix évitera considérablement les erreurs inconnues et réduira considérablement la charge de travail à long terme.
Les objectifs de l'optimisation du code sont:
1. Réduire le volume du code
2. Améliorer l'efficacité de l'opération de code
Certains contenus de cet article proviennent d'Internet, et certains viennent du travail et des études quotidiens. Bien sûr, ce n'est pas important. Ce qui est important, c'est de savoir si les détails de ces optimisations de code sont vraiment utiles. Ensuite, cet article sera mis à jour pendant longtemps. Tant que vous rencontrez des détails d'optimisation de code qui méritent d'être partagés, cet article sera mis à jour de temps à autre.
Détails d'optimisation du code
(1) Essayez de spécifier autant que possible le modificateur final de la classe et de la méthode
Les classes avec les modificateurs finaux ne sont pas dérivées. Dans l'API Java Core, il existe de nombreux exemples d'application finale, tels que java.lang.string, et toute la classe est finale. La spécification d'un modificateur final pour une classe peut empêcher la classe d'être héritée, et la spécification d'un modificateur final pour une méthode peut empêcher que la méthode d'être remplacée. Si une classe est spécifiée comme final, toutes les méthodes de cette classe sont finales. Le compilateur Java cherchera des opportunités pour alimenter toutes les méthodes finales. La ligne est d'une grande importance pour améliorer l'efficacité de course de Java. Pour plus de détails, voir l'optimisation de l'exécution de Java. Cette décision peut améliorer les performances en moyenne de 50%.
(2) Essayez de réutiliser les objets
Surtout pour l'utilisation d'objets String, StringBuilder / StringBuffer doit être utilisé à la place lorsque la concaténation de la chaîne se produit. Étant donné que les machines virtuelles Java ont non seulement besoin de passer du temps à générer des objets, ils peuvent également avoir besoin de passer du temps à collecter et de traiter ces objets à l'avenir, la génération trop d'objets aura un grand impact sur les performances du programme.
(3) utiliser autant que possible les variables locales
Les paramètres passés lors de l'appel de la méthode et des variables temporaires créées dans l'appel sont stockées sur la pile, ce qui est plus rapide. D'autres variables, telles que des variables statiques, des variables d'instance, etc., sont toutes créées dans le tas, ce qui est plus lent. De plus, comme les variables créées dans la pile sont terminées, ces contenus ont disparu et aucune collection de déchets supplémentaire n'est requise.
(4) fermer le flux dans le temps
Pendant la programmation Java, soyez prudent lorsque vous effectuez des opérations de connexion de base de données et de streaming d'E / S. Après utilisation, fermez-le à temps pour libérer les ressources. Parce que le fonctionnement de ces grands objets provoquera des frais généraux du système et si vous ne faites pas attention, cela entraînera de graves conséquences.
(5) minimiser les calculs répétés des variables
Pour clarifier un concept, même s'il n'y a qu'une seule phrase dans la méthode, elle est toujours consommée, y compris la création de cadres de pile, la protection du site lors de l'appel de la méthode et de la restauration du site lors de l'appel de la méthode. Ainsi, par exemple, l'opération suivante:
pour (int i = 0; i <list.size (); i ++) {...}Il est recommandé de le remplacer par:
pour (int i = 0, longueur = list.size (); i <longueur; i ++) {...}De cette façon, lorsque list.size () est très important, il réduit beaucoup de consommation
(6) Essayez d'adopter une stratégie de chargement paresseuse, c'est-à-dire en cas de besoin
Par exemple:
String str = "aaa"; if (i == 1) {list.add (str);}Il est recommandé de le remplacer par:
if (i == 1) {String str = "aaa"; list.add (str);}(7) utiliser des anomalies avec prudence
L'anomalie n'est pas bonne pour la performance. Pour lancer une exception, vous devez d'abord créer un nouvel objet. Le constructeur de l'interface jetable appelle la méthode de synchronisation locale nommée FillInstackTrace (). La méthode FILLINSTACKTRACE () vérifie la pile et collecte des informations de trace d'appel. Tant qu'une exception est lancée, la machine virtuelle Java doit ajuster la pile d'appels car un nouvel objet est créé pendant le traitement. Les exceptions ne peuvent être utilisées que pour la gestion des erreurs et ne doivent pas être utilisées pour contrôler le flux du programme.
(8) N'utilisez pas d'essayer ... Catch ... en boucle, il doit être placé sur la couche la plus externe
Selon les opinions avancées par les internautes, je pense que cela vaut la peine d'être discuté
(9) Si la longueur du contenu à ajouter peut être estimée, spécifiez la longueur initiale pour la collection et les classes d'outils implémentées dans un tableau sur la couche sous-jacente.
Par exemple, ArrayList, LinkedLlist, StringBuilder, StringBuffer, Hashmap, HashSet, etc. Prenez StringBuilder comme exemple:
StringBuilder () // Alloue par défaut 16 caractères de l'espace StringBuilder (int taille) // Alloue par défaut 16 caractères de l'espace StringBuilder (String Str) // Alloue par défaut 16 caractères + str.length () Space de caractères
Sa capacité d'initialisation peut être définie via le constructeur de la classe (ici, nous nous référons non seulement à StringBuilder ci-dessus), ce qui peut améliorer considérablement les performances. Par exemple, StringBuilder, la longueur représente le nombre de caractères que le stringbuilder actuel peut maintenir. Étant donné que lorsque StringBuilder atteint sa capacité maximale, elle augmentera sa propre capacité à 2 fois et en ajoutera 2. Chaque fois que StringBuilder atteindra sa capacité maximale, il devra créer un nouveau tableau de caractères et copier l'ancien contenu de tableau de caractères dans le nouveau tableau de caractères - il s'agit d'une opération très consommatrice de performances. Imaginez simplement, si vous pouvez estimer que 5000 caractères sont stockés dans le tableau de caractères sans spécifier la longueur, la puissance de 2 la plus proche de 5000 est 4096, et les 2 ajoutées à chaque expansion sont quel que soit le 2, alors: alors:
Sur la base de 4096, demandez des réseaux de caractères de taille 8194, qui s'ajoutent à des réseaux de caractères de taille 12290 à la fois. Si vous pouvez spécifier des tableaux de caractères de taille 5000 au début, vous économiserez plus du double de l'espace pour copier les caractères 4096 d'origine dans le nouveau tableau de caractères.
Cela gaspille non seulement l'espace mémoire, mais réduit également l'efficacité du fonctionnement du code. Par conséquent, il n'est pas faux de définir une capacité d'initialisation raisonnable pour les classes de collecte et d'outils implémentées dans le tableau sous-jacent, ce qui apportera des résultats immédiats. Cependant, notez que les collections comme HashMap qui sont implémentées dans les tableaux + listes liées ne doivent pas définir la taille initiale de la même manière que votre taille estimée, car la possibilité d'un seul objet connecté à un tableau est presque 0. Il est recommandé de définir la taille initiale sur N Power de 2. Si vous pouvez estimer qu'il existe 2 000 éléments, le définir sur un nouveau hashmap (128) et New Hashmap (256).
(10) Lors de la copie d'une grande quantité de données, utilisez la commande System.ArrayCopy ()
(11) Multiplication et Division Utiliser les opérations
Par exemple:
pour (val = 0; val <100000; val + = 5) {a = val * 8; b = val / 2;}L'utilisation des opérations de décalage peut améliorer considérablement les performances, car au bas de l'ordinateur, l'opération de positionnement est la plus pratique et la plus rapide, il est donc recommandé de le modifier pour:
pour (val = 0; val <100000; val + = 5) {a = val << 3; b = val >> 1;}Bien que l'opération Shift soit rapide, elle peut rendre le code difficile à comprendre, il est donc préférable d'ajouter des commentaires correspondants.
(12) Ne créez pas constamment des références d'objets dans la boucle
Par exemple:
pour (int i = 1; i <= count; i ++) {objet obj = nouveau objet (); }Cette approche entraînera l'exister la référence de l'objet d'objet dans la mémoire. Si le nombre est grand, il consommera la mémoire. Il est recommandé de le changer en:
Objet obj = null; pour (int i = 0; i <= count; i ++) {obj = nouvel objet ();}De cette façon, il n'y a qu'une seule référence d'objet d'objet en mémoire. Chaque fois que le nouvel objet () est utilisé, la référence de l'objet objet pointe vers un objet différent, mais il n'y a qu'un seul objet en mémoire, qui enregistre considérablement l'espace mémoire.
(13) Sur la base de la prise en compte de l'efficacité et de la vérification des types, le tableau doit être utilisé autant que possible. ArrayList ne doit être utilisé que si la taille du tableau ne peut pas être déterminée.
(14) Essayez d'utiliser HashMap, ArrayList et StringBuilder. À moins qu'il ne soit nécessaire pour la sécurité des threads, il n'est pas recommandé d'utiliser le hashtable, le vecteur et le stringbuffer. Les trois derniers ont des frais généraux de performance en raison de l'utilisation de mécanismes de synchronisation.
(15) Ne déclarez pas les tableaux comme finale statique publique
Parce que cela n'a pas de sens, il définit la référence comme finale statique, et le contenu du tableau peut toujours être modifié à volonté. Déclarer le tableau en tant que public est une vulnérabilité de sécurité, ce qui signifie que le tableau peut être modifié par des classes externes
(16) Essayez d'utiliser des cas uniques dans des occasions appropriées
L'utilisation des singletons peut réduire la charge de charge, raccourcir le temps de chargement et améliorer l'efficacité de charge, mais tous les endroits ne conviennent pas aux singletons. Autrement dit, les singletons sont principalement applicables aux trois aspects suivants:
Contrôlez l'utilisation des ressources, contrôlez la génération d'instances de contrôle d'accès simultanées des ressources par le biais de la synchronisation des threads, afin d'atteindre le but d'économiser des ressources pour contrôler le partage des données et d'activer la communication entre plusieurs processus ou threads non liés sans établir des associations directes.
(17) Essayez d'éviter d'utiliser des variables statiques à volonté
Vous devez savoir que lorsqu'un objet est référencé par une variable définie comme un statique, GC ne recycle généralement pas la mémoire du tas occupé par l'objet, comme:
classe publique A {privé statique b b = new b (); }Pour le moment, le cycle de vie de la variable statique B est le même que celui de la classe A. Si la classe A n'est pas désinstallée, l'objet B pointé par référence B résidera en mémoire jusqu'à ce que le programme se termine
(18) Effacer les séances qui ne sont plus nécessaires à temps
Afin d'effacer les sessions qui ne sont plus actives, de nombreux serveurs d'applications ont un délai d'expiration de session par défaut, généralement 30 minutes. Lorsque le serveur d'applications doit enregistrer plus de sessions, en cas de mémoire insuffisante, le système d'exploitation transférera une partie des données vers le disque. Le serveur d'applications peut également vider certaines sessions inactives sur le disque en fonction de l'algorithme MRU (le plus fréquemment utilisé) et peut même lancer des exceptions de mémoire insuffisantes. Si la session doit être jetée sur le disque, elle doit d'abord être sérialisée. Dans les grappes à grande échelle, le sérialisation des objets coûte cher. Par conséquent, lorsque la session n'est plus nécessaire, la méthode invalidate () de httpSession doit être appelée à temps pour effacer la session.
(19) Une collection qui met en œuvre l'interface à accès aléatoire, comme ArrayList, devrait utiliser la boucle la plus courante au lieu de la boucle foreach pour traverser
Ceci est recommandé par JDK aux utilisateurs. L'explication par l'API JDK de l'interface RandomAccess est: l'implémentation de l'interface RandomAccess est utilisée pour indiquer qu'il prend en charge un accès aléatoire rapide. L'objectif principal de cette interface est de permettre aux algorithmes généraux de modifier leur comportement, afin qu'il puisse fournir de bonnes performances lorsqu'il est appliqué à des listes d'accès aléatoires ou continues. L'expérience pratique montre que si les instances de classe qui implémentent l'interface aléatoire sont accessibles au hasard, l'efficacité de l'utilisation d'ordinaires pour les boucles sera plus élevée que celle de l'utilisation de boucles foreach; Inversement, s'il est accessible séquentiellement, il sera plus efficace d'utiliser Iterator. Vous pouvez utiliser des codes similaires à ce qui suit pour porter des jugements:
if (list instanceof randomaccess) {for (int i = 0; i <list.size (); i ++) {}} else {iterator <?> iterator = list.iterable (); while (iterator.hasnext ()) {iterator.next ()}}Le principe de mise en œuvre sous-jacent de la boucle foreach est l'itérateur, voir Java Syntax Sugar 1: Paramètres de longueur variable et principe de boucle foreach. Ainsi, la seconde moitié de la phrase "inversement, si elle est accessible séquentiellement, l'utilisation d'Iterator sera plus efficace" signifie que les instances de classe accessibles séquentiellement sont traversées à l'aide d'une boucle FOREAC.
(20) Utiliser des blocs de code synchrones au lieu de la méthode de synchronisation
Ceci est déjà clairement indiqué dans le bloc de méthode de verrouillage synchronisé de l'article dans le module multithread. À moins qu'il ne puisse être déterminé que la méthode entière doit être synchronisée, essayez d'utiliser des blocs de code synchronisés pour éviter de synchroniser les codes qui n'ont pas besoin d'être synchronisés, ce qui affecte l'efficacité d'exécution du code.
(21) Déclarez la constante comme finale statique et nommez-la en capital
De cette façon, ces contenus peuvent être placés dans le pool constant pendant la compilation, en évitant le calcul des valeurs constantes générées pendant l'exécution. De plus, le nom du nom d'une constante en capital peut également faciliter la distinction entre les constantes et les variables
(22) Ne créez pas de quelques objets inutilisés, n'importez pas de classes inutilisées
Cela n'a aucun sens. Si "la valeur de la variable locale I n'est pas utilisée" et "L'importation java.util n'est jamais utilisée" apparaître dans le code, veuillez supprimer ces contenus inutiles
(23) Évitez d'utiliser la réflexion pendant le fonctionnement du programme
Pour plus d'informations, voir la réflexion. La réflexion est une fonction très puissante fournie par Java aux utilisateurs. Des fonctions puissantes signifient souvent une faible efficacité. Il n'est pas recommandé d'utiliser fréquemment le mécanisme de réflexion pendant l'opération du programme, en particulier la méthode d'invoquer de la méthode. S'il est effectivement nécessaire, une approche suggestive consiste à instancier un objet par la réflexion et à la mettre en mémoire lorsque le projet est démarré. L'utilisateur ne se soucie que de la vitesse de réponse la plus rapide lors de l'interaction avec le pair et ne se soucie pas du temps qu'il faut pour que le projet de pair commence.
(24) Utiliser le pool de connexions de la base de données et le pool de threads
Les deux pools sont utilisés pour réutiliser des objets, le premier évite l'ouverture et la fermeture fréquentes des connexions, et la seconde évite la création et la destruction fréquentes des fils
(25) Utilisez des flux d'entrée et de sortie tamponnés pour les opérations IO
Streams d'entrée et de sortie tamponnés, à savoir BufferedReader, BufferedWriter, BufferedInputStream, BufferedOutputStream, qui peut considérablement améliorer l'efficacité IO
(26) Utilisez ArrayList pour des scènes avec une insertion plus séquentielle et un accès aléatoire, et utilisez LinkedList pour des scènes avec plus de suppression d'éléments et d'insertion intermédiaire.
Ceci est connu en comprenant les principes d'ArrayList et de LinkedList
(27) Ne laissez pas trop de paramètres formels dans la méthode publique
La méthode publique est une méthode fournie au monde extérieur. Si vous donnez à ces méthodes trop de paramètres formels, il existe deux principaux inconvénients:
Violer l'idée de programmation orientée objet. Java souligne que tout est un objet. Trop de paramètres formels et ne correspondent pas à l'idée de programmation orientée objet. Trop de paramètres entraîneront inévitablement une augmentation de la probabilité d'erreur dans les appels de méthode.
Quant au nombre de «trop», référence à, 3 ou 4. Par exemple, nous utilisons JDBC pour écrire une méthode InsertStudentinfo. Il y a 10 champs d'information des étudiants à insérer dans la table des étudiants. Ces 10 paramètres peuvent être encapsulés dans une classe d'entité comme paramètres formels de la méthode d'insertion.
(28) Lorsque des variables de chaîne et des constantes de chaîne égales sont écrites devant les constantes de chaîne
Il s'agit d'une astuce relativement courante, s'il y a le code suivant:
String str = "123"; if (str.equals ("123")) {...}Il est recommandé de le modifier à:
String str = "123"; if ("123" .equals (str)) {...}Cela peut principalement éviter les exceptions du pointeur nul
(29) Veuillez savoir qu'en Java, il n'y a pas de différence entre si (i == 1) et si (1 == i), mais du point de vue des habitudes de lecture, il est recommandé d'utiliser l'ancien
Parfois, les gens demandent s'il y a une différence entre "if (i == 1)" et "if (1 == i)"? Cela commence par C / C ++.
En C / C ++, la condition de jugement "if (i == 1)" est valide, et elle est basée sur 0 et non 0. 0 signifie faux et non 0 signifie vrai. S'il y a un tel morceau de code:
int i = 2; if (i == 1) {...} else {...}C / C ++ juge que "i == 1" n'est pas valide, il est donc représenté par 0, c'est-à-dire faux. Mais si:
int i = 2; if (i = 1) {...} else {...}Si le programmeur écrit accidentellement "si (i == 1)" comme "if (i = 1)", alors il y aura un problème. Attribuez I à 1 dans If. Si vous déterminez que le contenu qu'il ne soit pas 0, le renvoyé vrai, mais je suis évidemment 2, et la valeur comparée est 1, le faux qui doit être renvoyé. Cette situation est très susceptible de se produire dans le développement de C / C ++ et provoquera des erreurs difficiles à comprendre. Par conséquent, afin d'éviter les opérations d'attribution incorrectes des développeurs dans les instructions IF, il est recommandé d'écrire l'instruction IF:
int i = 2; if (1 == i) {...} else {...}De cette façon, même si le développeur écrit accidentellement "1 = i", le compilateur C / C ++ peut le vérifier dès que possible, car nous pouvons attribuer une valeur variable I à 1, mais nous ne pouvons pas attribuer une valeur constante 1 à i.
Cependant, dans Java, la syntaxe "if (i = 1)" de C / C ++ est impossible à apparaître, car une fois cette syntaxe écrite, Java compilera et rapportera une erreur "Type Mismatch: Impossible de convertir de INT à Boolean". Cependant, bien qu'il n'y ait pas de différence sémantique entre "if (i == 1)" et "if (1 == i)" en Java, il serait préférable de recommander le premier en termes d'habitudes de lecture.
(30) N'utilisez pas la méthode toString () sur le tableau
Jetons un coup d'œil à ce qui est imprimé à l'aide de toString () pour les tableaux:
int i = 2; if (1 == i) {...} else {...}s'avérer:
I @ 18A992F
L'intention d'origine est d'imprimer le contenu du tableau, mais il peut entraîner une exception de pointeur nul car la référence du tableau est nul. Cependant, bien que cela n'ait pas de sens pour le tableau ToString (), le contenu de la collection peut être imprimé pour la collection toString (), car la classe parent de la collection, la méthode toString () de l'objet est réécrite.
(31) Ne faites pas de transformations de force vers le bas sur les types de données de base qui sont hors de portée
Cela n'obtiendra jamais le résultat souhaité:
public static void main (String [] args) {long l = 12345678901234l; int i = (int) l; System.out.println (i);}Nous pouvons nous attendre à en obtenir certains, mais le résultat est:
1942892530
Expliquez-le. Long en Java est de 8 octets avec 64 bits, donc la représentation de 12345678901234 dans l'ordinateur devrait être:
0000 0000 0000 0000 0000 1011 0011 1010 0111 0011 1100 1110 0010 1111 1111 0010
Une données de type INT est de 4 octets et 32 bits. Les 32 premiers bits de la chaîne ci-dessus de données binaires sont tirées du bit bas:
0111 0011 1100 1110 0010 1111 1111 0010
Cette chaîne de binaires est représentée comme décimal 1942892530, il s'agit donc de la sortie de contenu sur la console ci-dessus. À partir de cet exemple, nous pouvons tirer deux conclusions:
1. Le type de données par défaut du type entier est int, long L = 12345678901234L. Ce nombre a dépassé la plage d'intre, il y a donc un L à la fin, indiquant qu'il s'agit d'un numéro de type long. Soit dit en passant, le type par défaut de type de point flottant est double, donc lors de la définition du flotteur, il doit être écrit comme "" float f = 3,5f "
2. Ensuite, écrivez une autre phrase "int ii = l + i;" et rapportera une erreur car long + int est long et ne peut pas être affecté à Int
(32) Les données non utilisées dans la classe de collecte publique doivent être supprimées à temps
Si une classe de collecte est publique (c'est-à-dire ce n'est pas une propriété dans une méthode), alors les éléments de cette collection ne seront pas automatiquement publiés car il y a toujours des références qui les pointent. Par conséquent, si certaines données dans la collecte publique ne sont pas utilisées et qu'elles ne sont pas supprimées, cela entraînera une croissance de la collection publique, ce qui fait que le système a le potentiel de fuite de mémoire.
(33) Convertir un type de données de base en une chaîne. Le type de données de base.toString () est le moyen le plus rapide, suivi de String.Valueof (données), et Data + "" est le plus lent
Il existe généralement trois façons de convertir un type de données de base. J'ai des données de type entier, c'est-à-dire toString (), string.valueof (i) et i + "" trois façons. Quelle est l'efficacité des trois façons? Voir un test:
public static void main (String [] args) {int loopTime = 50000; Entier i = 0; Long startTime = System.CurrentTimemillis (); pour (int j = 0; j <looptime; j ++) {String str = string.valueof (i); } System.out.println ("string.valueof ():" + (System.currentTimemillis () - starttime) + "ms"); startTime = System.CurrentTimemillis (); pour (int j = 0; j <looptime; j ++) {String str = i.toString (); } System.out.println ("Integer.ToString ():" + (System.currentTimemillis () - starttime) + "MS"); startTime = System.CurrentTimemillis (); pour (int j = 0; j <looptime; j ++) {String str = i + ""; } System.out.println ("i + /" / ":" + (System.currentTimemillis () - starttime) + "ms");}Le résultat en cours est:
String.ValueOf (): 11msInteger.ToString (): 5ms + "": 25ms
Par conséquent, lorsque vous convertissez un type de données de base en chaîne à l'avenir, vous devez donner la priorité à l'utilisation de la méthode toString (). Quant à pourquoi, c'est très simple:
String.valueOf() est appelée Integer.toString() , mais il court de juger Integer.toString() avant d'appeler. J'appellerai le i + "" La couche inférieure utilise l'implémentation StringBuilder. Utilisez d'abord la méthode APPEND pour l'épisser, puis utilisez la méthode toString () pour obtenir la chaîne.
Comparé aux trois, c'est évidemment le plus rapide, le plus rapide, le plus lent
(34) Utilisez le moyen le plus efficace pour traverser la carte
Il existe de nombreuses façons de traverser la carte. Habituellement, ce dont nous avons besoin pour traverser la clé et la valeur de la carte. La méthode recommandée et la plus efficace est:
public static void main (string [] args) {hashmap <string, string> hm = new hashmap <string, string> (); hm.put ("111", "222"); Set <map.entry <string, string >> entrySet = hm.EntrySet (); Iterator <map.entry <string, string >> iter = entryset.iterator (); while (iter.hasnext ()) {map.entry <string, string> entry = iter.next (); System.out.println (entry.getKey () + "/ t" + entrée.getValue ()); }} Si vous voulez simplement parcourir la valeur clé de cette carte, il serait plus approprié d'utiliser " Set<String> keySet = hm.keySet();"
(35) Il est recommandé de fonctionner séparément pour clôture () des ressources
Cela signifie, par exemple, j'ai un morceau de code comme celui-ci:
essayez {xxx.close (); Yyy.close ();} catch (exception e) {...}Il est recommandé de le modifier à:
try {xxx.close ();} catch (exception e) {...} try {yyy.close ();} catch (exception e) {...}Bien qu'il soit un peu gênant, cela peut éviter la fuite des ressources. Nous pensons que s'il n'y a pas de code modifié, si xxx.close () lance une exception, il entrera dans le bloc de capture. Yyy.close () ne sera pas exécuté et la ressource Yyy ne sera pas recyclée et sera occupée tout le temps. Avec plus de codes comme celui-ci, cela peut entraîner la divulgation de la poignée de ressource. Après avoir passé à la méthode d'écriture suivante, il est garanti que XXX et YYY seront fermés quoi qu'il arrive.
(36) Pour ThreadLocal, vous devez supprimer avant ou après utilisation
Actuellement, essentiellement tous les projets utilisent une technologie de mise en filetage, ce qui est très bon. Vous pouvez configurer dynamiquement le nombre de threads et de réutilisation des threads.
Cependant, si vous utilisez ThreadLocal dans votre projet, n'oubliez pas de le supprimer avant ou après l'utilisation. En effet, la technologie de pool de threads mentionnée ci-dessus est de réutiliser un fil, ce qui signifie que pendant le code en cours d'exécution, un fil ne sera pas détruit et attendra la prochaine utilisation. Jetons un coup d'œil à la référence dans la classe de threads qui contient threadLocal.ThreadLocalmap:
/ * Valeurs threadlocal relatives à ce fil. Cette carte est maintenue * par la classe threadlocal. * / ThreadLocal.ThreadLocalmap ThreadLocals = null;
Le thread n'est pas détruit signifie que les données du threadLocal.ThreadLocalmap de l'ensemble de threads précédent existent toujours. Lorsque le prochain thread réutilise ce fil, il est probable que ce que vous obtenez est les données de l'ensemble de threads précédent plutôt que le contenu que vous souhaitez.
Ce problème est très obscur. Une fois que les erreurs causées par cette cause se produisent, il est très difficile de trouver ce problème sans expérience pertinente ni fondation solide. Par conséquent, vous devez y prêter attention lors de la rédaction de code, ce qui réduira votre charge de travail ultérieure.
(37) N'oubliez pas de remplacer le nombre de diable par une définition constante. L'existence du nombre de diable réduira considérablement la lisibilité du code. Que les constantes de chaîne utilisent des définitions constantes peuvent dépendre de la situation.
(38) Lorsque l'attribution initiale de longue ou long, utilisez la majuscules L au lieu de minuscules L, car la lettre L est très facile à confondre avec le numéro 1, ce point est très détaillé et mérite d'être noté
(39) Toutes les méthodes de réécriture doivent conserver l'annotation @Override
Il y a trois raisons de faire cela:
(1) Il est clair que cette méthode est héritée de la classe parentale
(2) getObject () et get0bject () Méthodes. La quatrième lettre du premier est "O", et le quatrième parent et enfant de la seconde est "0". L'ajout de l'annotation @Override peut immédiatement déterminer si la réécriture est réussie.
(3) Modifier la signature de la méthode dans la classe abstraite et la classe d'implémentation rapportera immédiatement une erreur de compilation.
(40) Il est recommandé d'utiliser la classe d'outils d'objets nouvellement introduite dans JDK7 pour comparer les objets égaux, directement a.equals (b), et il existe un risque d'exceptions de pointeur nul.
(41) N'utilisez pas "+" pour épisser les chaînes dans le corps de la boucle, mais utilisez StringBuilder pour ajouter en continu
Permettez-moi de parler de la raison pour laquelle je n'utilise pas "+" pour l'épissage de cordes. Si j'ai une méthode:
public String A SPEndSTR (String oristr, String ... A SPENDSTRS) {if (appendStrs == null || APPENDSTRS.LONGT == 0) {return oRstr; } pour (String A SPEndSTR: A SPENDSTRS) {ORIRT + = APPDENCETR; } return oRstr;}Après avoir compilé ce code, décompile le fichier .class à l'aide de Javap -C pour intercepter la partie clé:
Cela signifie que chaque fois que la machine virtuelle rencontre l'opérateur "+" pour épisser la chaîne, il ne fait pas besoin d'un stringbuilder, puis appellera la méthode de l'annexe et appellera enfin la méthode toString () pour convertir la chaîne en objet ORIRST. Autrement dit, combien de fois la boucle sera New StringBuilder (), qui est un gaspillage de mémoire.
(42) Ne capture pas la classe d'exception d'exécution définie dans la bibliothèque de classe Java héritée de RuntimeException
L'efficacité de gestion des exceptions est faible, la plupart des classes d'exception d'exécution de RuntimeException peuvent être complètement évitées par les programmeurs, tels que:
(43) Évitez d'utiliser des instances aléatoires par plusieurs threads. Bien que le partage de l'instance soit en filetage, il entraînera une dégradation des performances en raison de la concurrence pour la même graine. Après JDK7, vous pouvez utiliser ThreadLocalrandom pour obtenir des nombres aléatoires
Expliquez la raison pour laquelle la concurrence pour la même graine provoque une dégradation des performances. Par exemple, jetez un œil à l'implémentation de la méthode suivante () de la classe aléatoire:
public int nextInt () {return net (32); }La méthode suivante (int bits) est appelée, qui est une méthode protégée:
protégé int next (int bits) {long oldseed, nextseed; Graine atomiclong = this.seed; do {oldseed = semed.get (); NextSeed = (OldSeed * Multiplicateur + Addend) & Mask; } while (! Seed ........ return (int) (nextseed >>> (48 - bits));}Et la graine ici est une variable globale:
/ ** * L'état interne associé à ce générateur de nombres pseudorandom. * (Les spécifications pour les méthodes de cette classe décrivent le calcul en cours * de cette valeur.) * / Graine atomiclong finale privée;
Lorsque plusieurs threads obtiennent des nombres aléatoires en même temps, ils rivaliseront pour la même graine, entraînant une diminution de l'efficacité.
(44) Les classes statiques, les cours de singleton et les cours d'usine ont mis leurs constructeurs à
C'est parce que nous n'avons pas besoin de les nouveaux à l'extérieur. Après avoir défini le constructeur sur privé, nous nous assurons que ces classes ne produisent pas d'objets d'instance.
post-scriptum
Un excellent code vient de chaque petite optimisation. Faire attention à chaque détail peut non seulement améliorer l'efficacité du fonctionnement du programme, mais également éviter de nombreux problèmes inconnus.
Ce qui précède est 44 suggestions d'optimisation de code Java introduites par l'éditeur. J'espère que cela vous sera utile. Si vous avez des questions, veuillez me laisser un message et l'éditeur vous répondra à temps. Merci beaucoup pour votre soutien au site Web Wulin.com!