Vorwort
Ich habe es im März 2016 überarbeitet und wieder besucht, warum ich den Code basierend auf meiner eigenen Arbeit und meiner täglichen Lernerfahrung optimieren muss. Bevor ich geändert habe, war meine Aussage so:
Genau wie ein Wal, das Garnelen isst, ist es für Wale nicht sehr effektiv, ein oder zwei Garnelen zu essen, aber wenn Sie zu viel Garnelen essen, sind die Wale natürlich voll. Die Codeoptimierung ist gleich. Vielleicht ist ein oder zwei Optimierungen von geringer Bedeutung für die Verbesserung der laufenden Effizienz des Codes. Solange Sie jedoch überall auf die Codeoptimierung achten können, ist dies im Allgemeinen sehr nützlich, um die laufende Effizienz des Codes zu verbessern.
Diese Ansicht ist in der vorliegenden Ansicht ein Grund für die Codeoptimierung, ist jedoch nicht vollständig korrekt. Mit der Entwicklung mechanischer Technologie haben Server heute häufig 8 Kerne, 16 Kerne und 64-Bit-CPUs, und die Codeausführungseffizienz ist sehr hoch. StringBuilder ersetzt StringBuffer und ArrayList ersetzt Vektor, wodurch die Effizienz des Codebetriebs durch winziges Verbesserung verbessert wird. Selbst wenn Sie jeden Punkt im Projekt bemerken, können Sie keine offensichtlichen Änderungen im Codevorgang erkennen.
Ich denke, die wichtigste Rolle der Codeoptimierung sollte sein: Unbekannte Fehler zu vermeiden. Während des Online -Codes treten häufig viele unerwartete Fehler auf, da die Online -Umgebung und die Entwicklungsumgebung sehr unterschiedlich sind, und die Fehlerpositionierung ist häufig ein sehr kleiner Grund. Um diesen Fehler zu lösen, müssen wir jedoch zuerst selbst überarbeiten und dann die Klassendatei ersetzen, das Geschäft aussetzen und neu starten. Für ein ausgereiftes Projekt hat das letzte tatsächlich einen großen Einfluss, was bedeutet, dass Benutzer in diesem Zeitraum nicht auf die Anwendung zugreifen können. Wenn Sie den Code schreiben, werden Sie daher auf lange Sicht auf verschiedene Details aus der Quelle, das Wiegen und die besten Auswahlmöglichkeiten beachten, die besten Auswahlmöglichkeiten wechseln und die Arbeitsbelastung auf lange Sicht erheblich verringern.
Die Ziele der Codeoptimierung sind:
1. Reduzieren Sie das Volumen des Codes
2. Verbessern Sie die Effizienz des Codebetriebs
Einige der Inhalte dieses Artikels stammen aus dem Internet und einige stammen aus der täglichen Arbeit und dem Studium. Das ist natürlich nicht wichtig. Wichtig ist, ob die Details dieser Codeoptimierung wirklich nützlich sind. Dann wird dieser Artikel lange Zeit aktualisiert. Solange Sie auf Code -Optimierungsdetails stoßen, die es wert sind, geteilt zu werden, wird dieser Artikel von Zeit zu Zeit aktualisiert.
Code -Optimierungsdetails
(1) Versuchen Sie, den endgültigen Modifikator der Klasse und Methode so weit wie möglich anzugeben
Klassen mit endgültigen Modifikatoren sind nicht abgeleitet. In der Java -Kern -API gibt es viele Beispiele für die endgültige Anwendung, wie Java.lang.String, und die gesamte Klasse ist endgültig. Wenn Sie einen endgültigen Modifikator für eine Klasse angeben, können Sie verhindern, dass die Klasse vererbt wird, und das Angeben eines endgültigen Modifikators für eine Methode kann verhindern, dass die Methode überschrieben wird. Wenn eine Klasse als endgültig angegeben ist, sind alle Methoden dieser Klasse endgültig. Der Java -Compiler wird nach Möglichkeiten suchen, alle endgültigen Methoden zu inline. Inline ist von großer Bedeutung für die Verbesserung der Laufeffizienz von Java. Weitere Informationen finden Sie in der Java -Laufzeitoptimierung. Dieser Schritt kann die Leistung durchschnittlich 50%verbessern.
(2) Versuchen Sie, Objekte wiederzuverwenden
Insbesondere für die Verwendung von String -Objekten sollte StringBuilder/StringBuffer stattdessen verwendet werden, wenn eine String -Verkettung auftritt. Da Java -Virtual -Maschinen nicht nur Zeit damit verbringen müssen, Objekte zu generieren, müssen sie möglicherweise auch Zeit damit verbringen, diese Objekte in Zukunft zu sammeln und zu verarbeiten. Die Erzeugung zu viele Objekte hat einen großen Einfluss auf die Leistung des Programms.
(3) Verwenden Sie so weit wie möglich lokale Variablen
Die Parameter, die beim Aufrufen der Methode und die im Anruf erstellten temporären Variablen übergeben wurden, werden auf dem Stapel gespeichert, was schneller ist. Andere Variablen, wie z. B. statische Variablen, Instanzvariablen usw., werden im Haufen erstellt, was langsamer ist. Da die im Stapel erstellten Variablen abgeschlossen sind, sind diese Inhalte weg und es ist keine zusätzliche Müllsammlung erforderlich.
(4) Schließen Sie den Fluss rechtzeitig
Seien Sie während der Java -Programmierung vorsichtig, wenn Sie die Datenbankverbindung und I/A -Streaming -Vorgänge ausführen. Schließen Sie es nach dem Gebrauch rechtzeitig, um Ressourcen freizugeben. Da der Betrieb dieser großen Objekte große Systemaufwand verursacht und wenn Sie nicht vorsichtig sind, führt dies zu schwerwiegenden Folgen.
(5) minimieren Sie wiederholte Berechnungen von Variablen
Um ein Konzept zu verdeutlichen, wird es weiterhin konsumiert, auch wenn es nur einen Satz in der Methode enthält, einschließlich des Erstellens von Stapelrahmen, dem Schutz der Website beim Aufrufen der Methode und der Wiederherstellung der Site beim Aufrufen der Methode. Zum Beispiel die folgende Operation:
für (int i = 0; i <list.size (); i ++) {...}Es wird empfohlen, es durch zu ersetzen:
für (int i = 0, länge = list.size (); i <länge; i ++) {...}Auf diese Weise reduziert es, wenn list.size () sehr groß ist
(6) versuchen
Zum Beispiel:
String str = "aaa"; if (i == 1) {list.add (str);}Es wird empfohlen, es durch zu ersetzen:
if (i == 1) {string str = "aaa"; list.add (str);}(7) Verwenden Sie Anomalien mit Vorsicht
Abnormalität ist nicht gut für die Leistung. Um eine Ausnahme auszulösen, müssen Sie zunächst ein neues Objekt erstellen. Der Konstruktor der Throwable Interface ruft die lokale Synchronisationsmethode mit dem Namen FillInstacktrace () auf. Die Methode FillInstackTrace () überprüft den Stapel und sammelt Call Trace -Informationen. Solange eine Ausnahme ausgelöst wird, muss die java virtuelle Maschine den Anrufstapel anpassen, da während der Verarbeitung ein neues Objekt erstellt wird. Ausnahmen können nur für die Fehlerbehandlung verwendet werden und sollten nicht zur Steuerung des Programmflusses verwendet werden.
(8) Verwenden Sie keinen Versuch ... Fang ... In der Schleife sollte es auf der äußersten Schicht platziert werden
Nach den von den Internetnutzern vorgelegten Meinungen denke ich, dass dies diskutiert werden lohnt
(9) Wenn die zugeschätzte Länge des zugeschätzten Inhalts zugeschätzt werden kann, geben Sie die anfängliche Länge für die in einem Array auf der zugrunde liegenden Ebene implementierten Sammel- und Werkzeugklassen an.
Zum Beispiel ArrayList, Linkedllist, StringBuilder, StringBuffer, HashMap, Hashset usw. Nehmen Sie StringBuilder als Beispiel:
StringBuilder () // Default -Zuweisung 16 Zeichen von Space StringBuilder (int Größe) // Default -Zuweisung 16 Zeichen von Space StringBuilder (String Str) // Standard -Zuordnung 16 Zeichen + Str.Length () Zeichenspeicher
Die Initialisierungskapazität kann durch den Konstruktor der Klasse eingestellt werden (hier beziehen wir uns nicht nur auf den StringBuilder oben), was die Leistung erheblich verbessern kann. Zum Beispiel repräsentiert StringBuilder, Länge die Anzahl der Zeichen, die der aktuelle StringBuilder beibehalten kann. Denn wenn StringBuilder seine maximale Kapazität erreicht, erhöht er seine eigene Kapazität auf das zweifache und fügt 2 hinzu. Wenn StringBuilder seine maximale Kapazität erreicht, muss es ein neues Zeichenarray erstellen und den alten Charakter -Array -Inhalt in das neue Charakter -Array kopieren - dies ist eine sehr leistungsverreicherende Operation. Stellen Sie sich vor, wenn Sie schätzen können, dass 5000 Zeichen im Charakter -Array ohne Angabe der Länge gespeichert sind, beträgt die Leistung von 2, die 5000 am nächsten liegen, 4096, und die 2, die jeder Erweiterung hinzugefügt werden, ist unabhängig von den 2, dann:
Basierend auf 4096 beantragen Sie 8194-Charakter-Arrays, die gleichzeitig zu 12290-Charakter-Arrays addieren. Wenn Sie zu Beginn 5000-Zeichen-Arrays angeben können, sparen Sie mehr als doppelt so hoch wie der Platz für die ursprünglichen 4096 Zeichen in das neue Charakter-Array.
Dies verschwendet nicht nur den Speicherplatz, sondern reduziert auch den Code -Betriebseffizienz. Daher ist es nicht falsch, eine angemessene Initialisierungskapazität für die im zugrunde liegenden Array implementierten Sammel- und Werkzeugklassen festzulegen, wodurch sofortige Ergebnisse erzielt werden. Beachten Sie jedoch, dass Sammlungen wie HashMap, die in Arrays + verlinkten Listen implementiert sind, die Anfangsgröße nicht mit Ihrer geschätzten Größe festlegen sollten, da die Möglichkeit eines an eine Tabelle angeschlossenen Objekts fast 0 beträgt. Es wird empfohlen, die Anfangsgröße auf N -Power von 2 zu schätzen.
(10) Verwenden Sie beim Kopieren einer großen Datenmenge das System.ArrayCopy () Befehl
(11) Multiplikation und Division verwenden Verschiebungsvorgänge
Zum Beispiel:
für (val = 0; val <100000; val += 5) {a = val * 8; b = val / 2;}Die Verwendung von Schichtvorgängen kann die Leistung erheblich verbessern, da am unteren Rand des Computers der Positionierungsbetrieb am bequemsten und am schnellsten ist. Es wird daher empfohlen, sie an zu ändern::
für (val = 0; val <100000; val += 5) {a = val << 3; b = val >> 1;}Obwohl der Schaltvorgang schnell ist, kann der Code schwierig zu verstehen. Es ist daher am besten, entsprechende Kommentare hinzuzufügen.
(12) Erstellen Sie nicht ständig Objektreferenzen in der Schleife
Zum Beispiel:
für (int i = 1; i <= count; i ++) {Objekt obj = new Object (); }Dieser Ansatz führt zu dem Verweis des Zählenobjekts, auf das im Speicher existiert. Wenn die Anzahl groß ist, wird der Speicher verbraucht. Es wird empfohlen, es zu ändern in:
Objekt obj = null; für (int i = 0; i <= count; i ++) {obj = new Object ();}Auf diese Weise befindet sich im Speicher nur eine Objekt -Objektreferenz. Jedes Mal, wenn New Object () verwendet wird, verweist das Objekt -Objektverweis auf ein anderes Objekt, aber es gibt nur ein Objekt im Speicher, das den Speicherplatz stark speichert.
(13) Basierend auf der Berücksichtigung von Effizienz und Typprüfung sollte das Array so weit wie möglich verwendet werden. ArrayList sollte nur verwendet werden, wenn die Array -Größe nicht bestimmt werden kann.
(14) Versuchen Sie, HashMap, ArrayList und StringBuilder zu verwenden. Sofern nicht für die Gewindesicherheit erforderlich ist, wird nicht empfohlen, Hashtable, Vector und StringBuffer zu verwenden. Die letzten drei haben aufgrund der Verwendung von Synchronisationsmechanismen Leistungsaufwand.
(15) Erklären Sie Arrays nicht als öffentliches statisches Finale
Da dies bedeutungslos ist, definiert es nur die Referenz als statisches Finale, und der Inhalt des Arrays kann weiterhin nach Belieben geändert werden. Das Erklären des Arrays als öffentlich ist eine Sicherheitsanfälligkeit, was bedeutet, dass das Array durch externe Klassen geändert werden kann
(16) Versuchen Sie, einzelne Fälle in geeigneten Gelegenheiten zu verwenden
Die Verwendung von Singletons kann die Lastbelastung reduzieren, die Ladezeit verkürzen und die Ladeeffizienz verbessern, aber nicht alle Orte sind für Singletons geeignet. Einfach ausgedrückt, Singletons sind hauptsächlich für die folgenden drei Aspekte anwendbar:
Steuern Sie die Verwendung von Ressourcen, kontrollieren Sie die Erzeugung gleichzeitiger Ressourceninstanzen von Zugriffskontrolle durch Threadsynchronisation, um den Zweck des Speicherns von Ressourcen zur Steuerung der Datenaustausch zu erreichen und die Kommunikation zwischen mehreren nicht verwandten Prozessen oder Threads zu ermöglichen, ohne direkte Assoziationen festzulegen.
(17) versuchen, nach Belieben statische Variablen zu vermeiden
Sie sollten wissen, dass GC den vom Objekt besetzten Heap -Speicher normalerweise nicht recycelt, wenn ein Objekt durch eine als statische Variable definierte Variable referenziert wird, z. B.:
public class a {private static b b = neu B (); }Zu diesem Zeitpunkt entspricht der Lebenszyklus der statischen Variablen B wie der von Klasse A. Wenn die Klasse A nicht deinstalliert ist, wird das B -Objekt, auf das durch Referenz B hingewiesen wird, im Speicher, bis das Programm endet
(18) Löschen Sie die nicht mehr benötigten Sitzungen mehr rechtzeitig
Um Sitzungen zu löschen, die nicht mehr aktiv sind, haben viele Anwendungsserver eine Standard -Sitzungs -Zeitüberschreitung, normalerweise 30 Minuten. Wenn der Anwendungsserver mehr Sitzungen speichern muss, überträgt das Betriebssystem einen Teil der Daten auf die Festplatte. Der Anwendungsserver kann auch einige inaktive Sitzungen auf die Festplatte gemäß dem MRU -Algorithmus (am häufigsten verwendet) abgeben und kann sogar nicht genügend Speicherausnahmen ausführen. Wenn die Sitzung auf die Festplatte abgeladen werden soll, muss sie zuerst serialisiert werden. In groß angelegten Clustern ist die Serialisierung von Objekten teuer. Wenn die Sitzung nicht mehr benötigt wird, sollte die Methode von HTTPSession die ungültig () -Methode rechtzeitig aufgerufen werden, um die Sitzung zu löschen.
(19) Eine Sammlung, die eine zufällige Schnittstelle wie ArrayList implementiert
Dies wird von JDK an Benutzer empfohlen. Die Erklärung der JDK -API für die RandomAccess -Schnittstelle lautet: Die Implementierung der RandomAccess -Schnittstelle wird verwendet, um anzuzeigen, dass sie einen schnellen Zufallszugriff unterstützt. Der Hauptzweck dieser Schnittstelle ist es, allgemeine Algorithmen ihr Verhalten zu ändern, damit sie eine gute Leistung liefern kann, wenn sie auf zufällige oder kontinuierliche Zugriffslisten angewendet werden. Die praktische Erfahrung zeigt, dass bei der Implementierung von Klasseninstanzen, die die RandomAccess -Schnittstelle im Umlauf haben, zufällig zugegriffen werden, auf die Effizienz der Verwendung normaler für Schleifen höher ist als die Verwendung von Foreach -Schleifen. Umgekehrt ist es effizienter, Iterator zu verwenden, wenn sie nacheinander zugegriffen werden. Sie können Codes verwenden, die den folgenden ähnlichen, um Urteile zu fällen:
if (listinstance von randomAccess) {for (int i = 0; i <list.size (); i ++) {}} else {iterator <?> iterator = list.Iterable (); while (iterator.hasnext ()) {iterator.next ()}}Das zugrunde liegende Implementierungsprinzip von foreach -Schleifen ist der Iterator, siehe Java -Syntaxzucker 1: Parameter der variablen Länge und Prinzip der Foreach -Schleife. Die zweite Hälfte des Satzes "umgekehrt, wenn nacheinander zugegriffen wird, ist die Verwendung von Iterator effizienter", dass die nacheinander zugegriffenen Klasseninstanzen mit einem Foreach -Schleifen durchquert werden.
(20) Verwenden Sie Synchroncodeblöcke anstelle der Synchronisationsmethode
Dies ist bereits im Artikel des Synchronisierungsverriegelungsblocks im Artikel im Multi-Thread-Modul deutlich angegeben. Versuchen Sie nicht festzustellen, dass die gesamte Methode synchronisiert werden muss, um synchronisierte Codeblöcke zu verwenden, um die Synchronisierung der Codes zu vermeiden, die nicht synchronisiert werden müssen, was die Codeausführungseffizienz beeinflusst.
(21) die Konstante als statisches Finale deklarieren und sie in Kapital benennen
Auf diese Weise können diese Inhalte während der Kompilierung in den konstanten Pool eingebaut werden, wodurch die Berechnung der erzeugten konstanten Werte während der Laufzeit vermieden werden. Darüber hinaus kann die Benennung des Namens einer Konstanten in Kapital auch die Unterscheidung zwischen Konstanten und Variablen erleichtern
(22) Erstellen Sie keine ungenutzten Objekte, importieren Sie einige nicht verwendete Klassen nicht
Das macht keinen Sinn. Wenn "der Wert der lokalen Variablen I nicht verwendet wird" und "Der Import java.util wird nie verwendet" im Code erscheinen, löschen Sie bitte diese nutzlosen Inhalte
(23) Vermeiden Sie die Verwendung von Reflexion während des Programmbetriebs
Weitere Informationen finden Sie unter Reflexion. Reflexion ist eine sehr leistungsstarke Funktion von Java für Benutzer. Leistungsstarke Funktionen bedeuten oft eine geringe Effizienz. Es wird nicht empfohlen, den Reflexionsmechanismus während des Programmvorgangs häufig zu verwenden, insbesondere die Methode der Methode. Wenn dies in der Tat notwendig ist, besteht ein suggestiver Ansatz darin, ein Objekt durch Reflexion zu instanziieren und es in den Speicher zu bringen, wenn das Projekt gestartet wird. Der Benutzer kümmert sich nur um die schnellste Reaktionsgeschwindigkeit, wenn sie mit dem Peer interagiert, und es ist egal, wie lange es dauert, bis das Peer -Projekt startet.
(24) Verwenden Sie den Datenbankverbindungspool und den Threadpool
Beide Pools werden zur Wiederverwendung von Objekten verwendet, erstere vermeidet häufiges Öffnen und Schließen von Verbindungen, und letzteres vermeidet häufige Schöpfung und Zerstörung von Fäden
(25) Verwenden Sie gepufferte Eingangs- und Ausgangsströme für IO -Operationen
Gepufferte Eingangs- und Ausgangsströme, nämlich BufferedReader, BufferedWriter, BufferedInputStream, BufferedOutputStream, der die IO -Effizienz erheblich verbessern kann
(26) Verwenden Sie ArrayList für Szenen mit sequentiellerem Einfügen und zufälliger Zugriff und verwenden Sie LinkedList für Szenen mit mehr Elementlöschung und Zwischeneinsatz.
Dies ist bekannt durch das Verständnis der Prinzipien von ArrayList und LinkedList
(27) Lassen Sie nicht zu viele formale Parameter in der öffentlichen Methode
Die öffentliche Methode ist eine Methode, die der Außenwelt zur Verfügung gestellt wird. Wenn Sie diesen Methoden zu viele formale Parameter angeben, gibt es zwei Hauptnachteile:
Verstoß gegen die objektorientierte Programmierungsidee. Java betont, dass alles ein Objekt ist. Zu viele formale Parameter und stimmen nicht mit der objektorientierten Programmierungsidee überein. Zu viele Parameter führen zwangsläufig zu einer Erhöhung der Fehlerwahrscheinlichkeit bei Methodenaufrufen.
Wie viele "zu viele" beziehen sich auf 3 oder 4. Zum Beispiel verwenden wir JDBC, um eine InsertStudentInfo -Methode zu schreiben. Es sind 10 Schülerinformationsfelder, die in die Schülertabelle eingefügt werden müssen. Diese 10 Parameter können in einer Entitätsklasse als formale Parameter der Einfügungsmethode eingekapselt werden.
(28) Wenn String -Variablen und String -Konstanten gleich vor Stringkonstanten geschrieben sind
Dies ist ein relativ häufiger Trick, wenn es den folgenden Code gibt:
String str = "123"; if (str.equals ("123") {...}Es wird empfohlen, es zu ändern an:
String str = "123"; if ("123" .Equals (str)) {...}Dies kann hauptsächlich Null -Zeigerausnahmen vermeiden
.
Manchmal fragen sich die Leute, ob es einen Unterschied zwischen "if (i == 1)" und "if (1 == i)" gibt? Dies beginnt mit C/C ++.
In C/C ++ ist die Beurteilungsbedingung "if (i == 1)" gültig und basiert auf 0 und Nicht-0. 0 bedeutet falsch und nicht 0 bedeutet wahr. Wenn es einen solchen Code gibt:
int i = 2; if (i == 1) {...} else {...}C/C ++ Richter, dass "i == 1" nicht gültig ist, daher wird es durch 0 dargestellt, dh false. Aber wenn:
int i = 2; if (i = 1) {...} else {...}Wenn der Programmierer versehentlich "if (i == 1)" als "if (i = 1)" schreibt, wird es ein Problem geben. Weisen Sie 1 zu 1 innerhalb if. Wenn Sie feststellen, dass der Inhalt darin nicht 0 ist, ist die zurückgegebene True, aber ich ist offensichtlich 2 und der verglichene Wert ist 1, das Falsch, das zurückgegeben werden sollte. Diese Situation tritt sehr wahrscheinlich bei der Entwicklung von C/C ++ auf und verursacht einige schwer verständliche Fehler. Um zu vermeiden, dass die falschen Zuweisungsvorgänge der Entwickler in iF -Anweisungen vermieden werden, wird empfohlen, die IF -Anweisung als zu schreiben:
int i = 2; if (1 == i) {...} else {...}Auf diese Weise kann der C/C ++ - Compiler ihn so schnell wie möglich aussehen, selbst wenn der Entwickler "1 = I" schreibt, da wir 1 so schnell wie möglich einen variablen Wert I zuweisen können, aber wir können i konstante Wert 1 nicht zuweisen.
In Java ist jedoch die "if (i = 1)" -Syntax von C/C ++ unmöglich zu erscheinen, da Java, sobald diese Syntax geschrieben ist, einen Fehler kompiliert und meldet. Obwohl es in Java keinen semantischen Unterschied zwischen "if (i == 1)" und "if (1 == i)" gibt, wäre es besser, die Verwendung der ersteren in Bezug auf Lesegewohnheiten zu empfehlen.
(30) Verwenden Sie die Methode toString () nicht auf dem Array
Schauen wir uns an, was mit TOString () für Arrays gedruckt wird:
int i = 2; if (1 == i) {...} else {...}sich herausstellen:
I@18a992f
Die ursprüngliche Absicht ist es, den Inhalt des Arrays auszudrucken, kann jedoch zu einer Ausnahme von Nullzeiger führen, da die Array -Referenz null ist. Obwohl es für das Array toString () nicht sinnvoll ist, kann der Inhalt in der Sammlung für die Sammlung toString () ausgedruckt werden, da die übergeordnete Klasse der Sammlung die Methode des Objekts umgeschrieben wird.
(31) Machen Sie keine Abwärts -Krafttransformationen an grundlegenden Datentypen, die außerhalb des Bereichs liegen
Dies wird niemals das gewünschte Ergebnis erzielen:
public static void main (String [] args) {long l = 12345678901234l; int i = (int) l; System.out.println (i);}Wir können erwarten, einige von ihnen zu bekommen, aber das Ergebnis ist:
1942892530
Erklären Sie es. Lange in Java liegt 8 Bytes mit 64 Bit, sodass die Darstellung von 12345678901234 im Computer:
0000 0000 0000 0000 0000 1011 0011 1010 0111 0011 1100 1110 0010 1111 1111 0010
Ein Int -Typ -Daten ist 4 Bytes und 32 Bit. Die ersten 32 Bit der obigen Binärdaten werden aus dem niedrigen Bit entnommen:
0111 0011 1100 1110 0010 1111 1111 0010
Diese Binärkette wird als Dezimalzahl von 1942892530 dargestellt, daher ist es die Inhaltsausgabe auf der obigen Konsole. Aus diesem Beispiel können wir zwei Schlussfolgerungen ziehen:
1. Der Standarddatentyp des Ganzzahltyps ist int, lang L = 12345678901234L. Diese Zahl hat den Bereich von INT überschritten, sodass am Ende ein L vorhanden ist, was darauf hinweist, dass dies eine lange Typzahl ist. Übrigens ist der Standardtyp des schwimmenden Punktes doppelt so hoch. Bei der Definition von Float sollte er als "" Float F = 3,5F "geschrieben werden.
2. Schreiben Sie als nächstes einen weiteren Satz "int ii = l + i;" und wird einen Fehler melden, weil Long + int lang ist und int nicht zugewiesen werden kann
(32) Die in der öffentlichen Sammlung nicht verwendeten Daten müssen rechtzeitig entfernt werden
Wenn eine Sammelklasse öffentlich ist (dh, handelt es sich nicht um eine Eigenschaft in einer Methode), dann werden die Elemente in dieser Sammlung nicht automatisch veröffentlicht, da immer Referenzen auf sie zeigen. Wenn bestimmte Daten in der öffentlichen Sammlung nicht verwendet werden und nicht entfernt werden, wird die öffentliche Sammlung weiter wächst, wodurch das System das Potenzial für Speicherleckage hat.
(33) Umwandeln Sie einen grundlegenden Datentyp in eine Zeichenfolge. Der grundlegende Datentyp.ToString () ist der schnellste Weg, gefolgt von String.Valueof (Daten), und Daten +"" ist der langsamste
Es gibt im Allgemeinen drei Möglichkeiten, einen grundlegenden Datentyp in die Konvertierung zu konvertieren. Ich habe eine Ganzzahl -Daten, d. H. ToString (), String.Valueof (i) und i+"" Drei Wege. Wie effizient sind die drei Wege? Siehe einen Test:
public static void main (String [] args) {int LoopTime = 50000; Ganzzahl i = 0; Long start time = system.currenttimemillis (); für (int j = 0; j <LoopTime; j ++) {String str = string.ValueOf (i); } System.out.println ("String.ValueOf ():" + (System.currentTimemillis () - StartTime) + "MS"); startTime = system.currentTimemillis (); für (int j = 0; j <LoopTime; j ++) {string str = i.toString (); } System.out.println ("Integer.toString ():" + (System.currentTimemillis () - StartTime) + "MS"); startTime = system.currentTimemillis (); für (int j = 0; j <LoopTime; j ++) {string str = i+""; } System.out.println ("i + /" /":" + (System.currentTimemillis () - StartTime) + "MS");}Das laufende Ergebnis ist:
String.ValueOf (): 11mSintereger.toString (): 5ms + "": 25ms
Wenn Sie in Zukunft einen grundlegenden Datentyp in String konvertieren, sollten Sie die Verwendung der Methode toString () Priorität geben. Was warum ist es sehr einfach:
String.valueOf() wird als Integer.toString() -Methode bezeichnet, aber es wird kurz, Integer.toString() zu beurteilen, bevor sie aufgerufen wird. Ich werde die I + "" "Die untere Schicht verwenden die StringBuilder -Implementierung. Verwenden Sie zunächst die Anhang -Methode, um sie zu spleißen, und verwenden Sie dann die Methode toString (), um die Zeichenfolge abzurufen.
Im Vergleich zu den drei ist es offensichtlich am schnellsten, am schnellsten, am langsamsten, am langsamsten
(34) Verwenden Sie den effizientesten Weg, um die Karte zu durchqueren
Es gibt viele Möglichkeiten, die Karte zu durchqueren. Normalerweise müssen wir den Schlüssel und den Wert in der Karte durchqueren. Die empfohlene und effizienteste Methode ist:
public static void main (String [] args) {HashMap <String, String> hm = new Hashmap <String, String> (); hm.put ("111", "222"); Set <map.Entry <String, String >> Eintragset = Hm.EntrySet (); Iterator <map.Entry <String, String >> iter = Eintragset.Iderator (); while (iter.hasnext ()) {map.Entery <string, string> einsteiger = iter.next (); System.out.println (Eintrag.getKey () + "/t" + Eintrag.getValue ()); }} Wenn Sie nur den Schlüsselwert dieser Karte iterieren möchten, ist es angemessener, " Set<String> keySet = hm.keySet();"
(35) Es wird empfohlen, separat für Close () von Ressourcen zu arbeiten
Es bedeutet zum Beispiel, dass ich ein Stück Code wie diesen habe:
try {xxx.close (); Yyy.close ();} catch (Ausnahme E) {...}Es wird empfohlen, es zu ändern an:
try {xxx.close ();} catch (Ausnahme E) {...} try {yyy.close ();} catch (Ausnahme E) {...}Obwohl es etwas problematisch ist, kann es Ressourcenleckage vermeiden. Wir denken, wenn xxx.close () keinen modifizierten Code gibt, wird er den Fangblock eingeben. Yyy.close () wird nicht ausgeführt und die YYY -Ressource wird nicht recycelt und ständig besetzt. Mit weiteren Codes wie diesem kann dies dazu führen, dass der Ressourcengriff durchgesickert wird. Nach dem Wechsel zu der folgenden Schreibmethode ist es garantiert, dass XXX und YYY unabhängig davon geschlossen werden.
(36) Für ThreadLocal müssen Sie vor oder nach dem Gebrauch entfernen
Derzeit verwenden alle Projekte Thread Pooling -Technologie, was sehr gut ist. Sie können die Anzahl der Threads dynamisch konfigurieren und Threads wiederverwenden.
Wenn Sie jedoch ThreadLocal in Ihrem Projekt verwenden, denken Sie daran, es vor oder nach dem Gebrauch zu entfernen. Dies liegt daran, dass die oben erwähnte Thread -Pool -Technologie darin besteht, einen Thread wiederzuverwenden, was bedeutet, dass während des Code -Liefs ein Thread nicht zerstört wird und auf die nächste Verwendung wartet. Schauen wir uns die Referenz in der Thread -Klasse an, in der ThreadLocal.ThreadLocalMap gehalten wird:
/* Threadlokalwerte zu diesem Thread. Diese Karte wird von der ThreadLocal -Klasse erhalten. */ThreadLocal.threadlocalMap threadLocals = null;
Der Thread wird nicht zerstört, dass die Daten im ThreadLocal.ThreadLocalMap des vorherigen Thread -Satzes noch vorhanden sind. Wenn der nächste Thread diesen Thread wiederverwendet, ist es wahrscheinlich, dass Sie die Daten des vorherigen Thread -Satzes und nicht den gewünschten Inhalt erhalten.
Dieses Problem ist sehr dunkel. Sobald Fehler durch diese Ursache verursacht wurden, ist es sehr schwierig, dieses Problem ohne relevante Erfahrung oder einer soliden Grundlage zu finden. Daher sollten Sie beim Schreiben von Code darauf achten, wodurch Ihre nachfolgende Arbeitsbelastung verringert wird.
(37) Denken Sie daran, die Teufelszahl durch konstante Definition zu ersetzen. Die Existenz der Teufelszahl wird die Lesbarkeit des Codes erheblich verringern. Ob String -Konstanten konstante Definitionen verwenden, kann von der Situation abhängen.
(38) Wenn die anfängliche Zuordnung von lang oder lang oder lang in Großbuchstaben L anstelle von Kleinbuchstaben L verwendet wird, da der Buchstaben L sehr einfach mit der Nummer 1 verwechselt werden kann, ist dieser Punkt sehr detailliert und erwähnenswert
(39) Alle Umschreibmethoden müssen die @Override -Annotation beibehalten
Es gibt drei Gründe dafür:
(1) Es ist klar, dass diese Methode von der übergeordneten Klasse geerbt wird
(2) GetObject () und Get0Bject () -Methoden. Der vierte Brief des ersteren ist "o" und das vierte Elternteil und das Kind des letzteren ist "0". Das Hinzufügen der @Override -Annotation kann sofort feststellen, ob das Umschreiben erfolgreich ist.
(3) Ändern Sie die Methodensignatur in der abstrakten Klasse, und die Implementierungsklasse meldet sofort einen Kompilierungsfehler.
(40) Es wird empfohlen, die neu eingeführte Objekt -Toolklasse in JDK7 zu verwenden, um Objekte gleich zu vergleichen, direkt A.equals (b), und es besteht das Risiko von Null -Zeiger -Ausnahmen.
(41) Verwenden Sie nicht "+", um Strings im Schleifenkörper zu spleißen, aber verwenden Sie StringBuilder, um kontinuierlich anzuhängen
Lassen Sie mich über den Grund sprechen, warum ich "+" für String -Spleißen nicht benutze. Wenn ich eine Methode habe:
public String appendstr (String oristr, String ... appendStRs) {if (appendStrs == null || appendstrs.length == 0) {return oristr; } für (String appendstr: appendStrs) {oristr += appendstr; } return oristr;}Dekompilieren Sie nach dem Kompilieren dieses Codes die .class -Datei mit Javap -c, um den Schlüsselteil abzufangen:
Dies bedeutet, dass jedes Mal, wenn der virtuelle Maschine auf den "+" -Operator trifft, um die Zeichenfolge zu spleißen, neu ein StringBuilder, dann die Append -Methode aufrufen und schließlich die Methode toString () aufrufen, um die Zeichenfolge in das ORISTR -Objekt umzuwandeln. Das heißt, wie oft wird die Schleife neuer StringBuilder (), was eine Speicherverschwendung ist.
(42) Erfassen Sie die in der Java -Klassenbibliothek definierte Laufzeit -Runtime -Ausnahmeklasse nicht von RunTimeException geerbt
Die Effizienz der Ausnahme der Ausnahme ist gering. Die meisten Laufzeitklassen von RunTimeException können von Programmierern vollständig vermieden werden, wie z. B.:
(43) Vermeiden Sie die Verwendung von zufälligen Instanzen nach mehreren Threads. Obwohl das Teilen der Instanz thread-sicher ist, wird dies aufgrund des Wettbewerbs um denselben Saatgut eine Leistungsverschlechterung verursachen. Nach JDK7 können Sie ThreadLocalRandom verwenden, um zufällige Zahlen zu erhalten
Erklären Sie den Grund, warum der Wettbewerb um denselben Saatgut die Leistungsverschlechterung verursacht. Schauen Sie sich beispielsweise die Implementierung der nächsten in der Methode der zufälligen Klasse an:
public int nextInt () {return next (32); }Die nächste Methode (int Bits) wird aufgerufen, eine geschützte Methode:
Protected Int Next (int Bits) {Long OldSeed, Nextseed; Atomiclong samen = this.seed; do {OldSeed = Seed.get (); Nextseed = (OldSeed * Multiplikator + Addend) & Mask; } while (! Seed.comPareandset (OldSeed, Nextseed)); return (int) (Nextseed >>> (48 - Bits));}Und der Samen hier ist eine globale Variable:
/*** Der mit diesem Pseudorandom -Zahlengenerator verbundene interne Zustand. * (Die Spezifikationen für die Methoden in dieser Klasse beschreiben die laufende * Berechnung dieses Wertes.) */ Private endgültige Atomiclong -Saatgut;
Wenn mehrere Threads gleichzeitig Zufallszahlen erhalten, konkurrieren sie um denselben Samen, was zu einer Verringerung der Effizienz führt.
(44) Statische Klassen, Singleton -Klassen und Fabrikklassen setzen ihre Konstrukteure auf privat
Dies liegt daran, dass wir sie draußen nicht neu neu machen müssen. Nachdem wir den Konstruktor auf privat eingestellt haben, stellen wir sicher, dass diese Klassen keine Instanzobjekte erzeugen.
PostScript
Hervorragender Code kommt von jeder kleinen Optimierung. Wenn Sie auf jedes Detail achten, können Sie nicht nur die laufende Effizienz des Programms verbessern, sondern auch viele unbekannte Probleme vermeiden.
Die oben genannten sind 44 Java -Code -Optimierungsvorschläge, die vom Editor eingeführt wurden. Ich hoffe, es wird Ihnen hilfreich sein. Wenn Sie Fragen haben, hinterlassen Sie mir bitte eine Nachricht und der Editor wird Ihnen rechtzeitig antworten. Vielen Dank für Ihre Unterstützung auf der Wulin.com -Website!