Bei der Java -Programmierung können einige Wissen nicht nur durch Sprachspezifikationen oder Standard -API -Dokumentation erlernt werden. In diesem Artikel werde ich versuchen, einige der am häufigsten verwendeten Redewendungen zu sammeln, insbesondere diejenigen, die schwer zu erraten sind.
Ich habe den gesamten Code in diesem Artikel an öffentlichen Orten eingesetzt. Sie können jeden Code -Snippet nach Ihren Vorlieben kopieren und ändern, ohne Anmeldeinformationen.
Implementierung gleich ()
Klasse Person {String Name; int Birthdayyear; Byte [] roh; public boolean gleich (Objekt obj) {if (! obj Instance von Person) return false; Person Andere = (Person) obj; return name.equals (other.name) && birthdayyear == other.birthyear && arrays.equals (raw, other.raw); } public int HashCode () {...}} Der Parameter muss vom Typ Objekt und nicht von einer peripheren Klasse sein.
Foo.equals (NULL) muss falsch zurückkehren und kann NullPointerexception nicht werfen. (Beachten Sie, dass die NULL -Instanz einer Klasse immer false zurückgibt, sodass der obige Code ausgeführt werden kann.)
Vergleich der grundlegenden Typdomänen (z. B. int) wird verwendet ==, und der Vergleich der grundlegenden Array -Domänen wird von arrays.equals () verwendet.
Denken Sie beim Überschreiben von Equals () daran, den HashCode () entsprechend zu überschreiben, um mit Equals () übereinzustimmen.
Referenz: java.lang.object.equals (Objekt).
HashCode implementieren ()
Klasse Person {String a; Objekt B; Byte C; int [] d; public int hashcode () {return a.hashcode () + b.hashcode () + c + arrays.hashcode (d); } public boolean gleich (Objekt o) {...}} Wenn die x- und y -Objekte x.equals (y) == true haben, müssen Sie sicherstellen, dass x.hashcode () == y.hashcode ().
Nach dem inversen Satz, wenn x.hashcode ()!
Sie müssen nicht garantieren, dass x.hashcode ()! = Y.hashcode () wenn x.equals (y) == false. Dies verbessert jedoch die Leistung der Hash -Tabelle, wenn Sie es so lange wie möglich machen können.
Die einfachste rechtliche Umsetzung von HashCode () besteht darin, einfach 0 zurückzugeben; Obwohl diese Implementierung korrekt ist, werden die Datenstrukturen wie HashMap sehr langsam ausgeführt.
Vergleicheto implementieren ()
Klasse Person implementiert vergleichbar <person> {String FirstName; String LastName; int Geburtstag; // Vergleiche von FirstName, Break Ties von LastName, schließlich brake bra Bindes by Birthdate public int vergleicheto (Person Andere) {if (firstName.comPareto (other.firstname)! sonst if (lastname.comPareto (other.lastName)! sonst wenn (Birthdate <other.birthdate) return -1; sonst wenn (birthdate> other.birthDate) zurückkehren 1; sonst return 0; }} Immer eine generische Version vergleichbar anstelle von primitivem Typ vergleichbar. Denn dies kann das Codevolumen sparen und unnötige Ärger reduzieren.
Kümmere dich nur um die Zeichen (negativ/Null/positiv), die das Ergebnis zurückgeben, und ihre Größe spielt keine Rolle.
Die Implementierung von Comparator.comPare () ähnelt dieser.
Clone () implementieren
Klassenwerte implementiert klonbar {String ABC; doppelt foo; int [] Bars; Datum eingestellt; öffentliche Werte clone () {try {values result = (values) super.clone (); result.bars = result.bars.clone (); result.Hired = result.hired.clone (); Rückgabeergebnis; } catch (clonenotsuptedEdException e) {// Impossible neue AssertionError (e); }}} Verwenden Sie Super.clone (), um die Objektklasse für das Erstellen neuer Objekte verantwortlich zu machen.
Die Grundtypdomänen wurden korrekt kopiert. Auch hier müssen wir keine unveränderlichen Typen wie String und Biginteger klonen.
Führen Sie die tiefe Kopie aller Felder (Objekte und Arrays) manuell durch.
Die klonbare Klasse wird implementiert und die Clone () -Methode sollte niemals eine Clonenotsupportededexception werfen. Daher müssen Sie diese Ausnahme fangen und ignorieren oder mit einer ungeprüften Ausnahme einwickeln.
Es ist in Ordnung und legal, die Clone () -Methode manuell zu implementieren, ohne die Methode von Object.clone () zu verwenden.
Verwenden Sie StringBuilder oder StringBuffer
// join (["a", "b", "c"]) -> "a und b und c" String Join (Liste <string> strs) {StringBuilder sb = new StringBuilder (); boolean zuerst = wahr; für (String S: strs) {if (zuerst) first = false; sonst sb.append ("und"); sb.Append (s); } return sb.toString ();} Verwenden Sie keine doppelte String -Verkettung wie folgt: S += Element, da seine Zeiteffizienz O (n^2) ist.
Bei Verwendung von StringBuilder oder StringBuffer können Sie die Methode append () verwenden, um Text hinzuzufügen und die Methode toString () zu verwenden, um den angeschlossenen gesamten Text zu erhalten.
Die Priorität wird StringBuilder vor Priorität gegeben, da sie schneller ist. Alle Methoden von StringBuffer werden synchronisiert und Sie benötigen normalerweise keine synchronisierte Methode.
Generieren Sie zufällige Ganzzahlen in einem Bereich
Random Rand = new random (); // zwischen 1 und 6, einschließlich diceroll () {return rand.nextint (6) + 1;} Verwenden Sie immer die Java -API -Methode, um eine zufällige Zahl im Bereich von Ganzzahlen zu generieren.
Versuchen Sie nicht, Math.abs (Rand.Nextint ()) %N für diese ungewisse Verwendungen zu verwenden, da die Ergebnisse voreingenommen sind. Darüber hinaus kann sein Ergebniswert negativ sein, z. B. wenn Rand.Nextint () == Integer.min_Value.
Iterator verwenden.remove ()
void filter (list <string> list) {for (iterator <string> iter = list.iterator (); iter.hasnext ();) {String item = iter.next (); if (...) iter.remove (); }}Die Methode von REME () wirkt sich auf den kürzlich zurückgegebenen Eintrag der nächsten () -Methode. Jeder Eintrag kann nur einmal die Methode von REME () verwenden.
Return String
String Reverse (String S) {return New StringBuilder (s) .Reverse (). ToString ();}Diese Methode sollte wahrscheinlich zur Java Standard Library hinzugefügt werden.
Starten Sie einen Thread
Die folgenden drei Beispiele tun dasselbe auf unterschiedliche Weise.
So implementieren Sie Runnnnable:
void startathread0 () {neuer Thread (neuer Myrunnable ()). start ();} Klasse Myrunnable Geräte Runnable {public void run () {...}}Wie man Thread erbt:
void startathread1 () {new myThread (). start ();} Klasse MyThead erweitert Thread {public void run () {...}}Wie man anonym Thread erben:
void startathread2 () {new thread () {public void run () {...}} .Start ();}Rufen Sie die Run () -Methode nicht direkt auf. Die Methode von Thread.start () wird immer aufgerufen, wodurch ein neuer Thread erstellt wird und den neu erstellten Thread Run () aufruft.
Verwenden Sie Versuch
E/A -Stream -Beispiel:
void WriteStuff () löscht ioException {outputStream out = new FileOutputStream (...); versuche {out.write (...); } endlich {out.close (); }}Lock -Beispiel:
void dowithlock (lock lock) {lock.acquire (); try {...} endlich {lock.release (); }} Wenn die Anweisung vor dem Versuch nicht ausgeführt wird und eine Ausnahme ausgelöst wird, wird der endgültige Anweisungsblock nicht ausgeführt. Unabhängig davon, was in diesem Beispiel nicht erforderlich ist, müssen Sie sich keine Sorgen um die Freigabe von Ressourcen machen.
Wenn die Anweisung in der Ausnahme in der Anweisung eine Ausnahme ausgelöst wird, wird das Ausführen des Programms zum endgültigen Anweisungsblock springen, um so viele Anweisungen wie möglich auszuführen und dann aus dieser Methode herauszukommen (es sei denn, diese Methode hat einen weiteren peripheren Anweisungsblock).
Lesen Sie Byte -Daten aus dem Eingabestream
InputStream in = (...); try {while (true) {int b = in.read (); if (b == -1) brechen; (... Prozess b ...)}} endlich {in.close ();}Die Read () -Methode gibt entweder die nächste Anzahl von Bytes zurück, die aus dem Stream (0 bis 255, einschließlich 0 und 255) gelesen wurden, oder -1, wenn das Ende des Streams erreicht ist.
Lesen Sie Blockdaten aus dem Eingabestream
InputStream in = (...); try {byte [] buf = new byte [100]; while (true) {int n = in.read (buf); if (n == -1) brechen; (... BUF mit Offset = 0 und Länge = n ...)}} endlich {in.close ();}Denken Sie daran, dass die Read () -Methode nicht unbedingt die gesamte BUF füllt, sodass Sie die Länge der Rückkehr in der Verarbeitungslogik berücksichtigen müssen.
Text aus einer Datei lesen
BufferedReader in = new bufferedReader (neuer InputStreamReader (neuer FileInputStream (...), "utf-8"); try {while (true) {String line = in.readline (); if (line == null) brechen; (... Prozesszeile ...)}} endlich {in.close ();} Die Schaffung des BufferedReader -Objekts scheint sehr ausführlich zu sein. Dies liegt daran, dass Java Bytes und Charaktere als zwei verschiedene Konzepte behandelt (dies unterscheidet sich von C).
Sie können jede Art von InputStream anstelle von FileInputStream wie Socket verwenden.
BufferedReader.readline () kehrt null zurück, wenn das Ende des Stroms erreicht ist.
Verwenden Sie die Methode reader.read (), um jeweils ein Zeichen zu lesen.
Sie können andere Zeichenkodierungen ohne UTF-8 verwenden, aber es ist besser, dies nicht zu tun.
Schreiben Sie Text in eine Datei
Printwriter out = neuer printwriter (neuer outputStreamWriter (neuer FileOutputStream (...), "utf-8"); try {out.print ("Hallo"); out.print (42); out.println ("Welt!");} endlich {out.close ();} Die Erstellung von Pressewriterobjekten scheint sehr ausführlich zu sein. Dies liegt daran, dass Java Bytes und Charaktere als zwei verschiedene Konzepte behandelt (dies unterscheidet sich von C).
Genau wie bei System.out können Sie Print () und println () verwenden, um mehrere Wertearten zu drucken.
Sie können andere Zeichenkodierungen ohne UTF-8 verwenden, aber es ist besser, dies nicht zu tun.
Defensiv -Überprüfungswert
int factorial (int n) {if (n <0) werfen neue illegalArgumentException ("undefined"); sonst wenn (n> = 13) neue Arithmexception ("Ergebnisüberlauf") werfen; sonst wenn (n == 0) zurücksender 1; sonst return n * factorial (n - 1);} Denken Sie nicht, dass die Eingangswerte positiv, klein genug sind usw., um diese Bedingungen explizit zu erkennen.
Eine gut gestaltete Funktion sollte in der Lage sein, für alle möglichen Eingabewerte korrekt auszuführen. Stellen Sie sicher, dass alle Situationen berücksichtigt werden und dass es keine falsche Ausgabe gibt (z. B. Überlauf).
Vorbeugende Testobjekte
int findIndex (list <string> list, String target) {if (list == null || target == null) werfen neue nullPointerexception (); ...}Denken Sie nicht, dass Objektparameter nicht null sind. Diese Erkrankung explizit zu erkennen.
Vorbeugung Erkennungsarray Index
void frob (byte [] b, int index) {if (b == null) werfen neue nullpointerexception (); if (index <0 || index> = b.Length) werfen neue indexoutofBoundSexception (); ...}Denken Sie nicht, dass der angegebene Array -Index die Grenzen nicht überschreitet. Es explizit zu erkennen.
Intervall für vorbeugende Erkennungsarray
void frob (byte [] b, int off, int len) {if (b == null) werfen neue nullpointerexception (); if (off <0 || off> B.Length || len <0 || b.Length - Aus <len) werfen neue indexoutofBoundSexception (); ...}Denken Sie nicht, dass das angegebene Array -Intervall (z. Es explizit zu erkennen.
Füllen Sie Array -Elemente
Verwenden von Schleifen:
// Jedes Element von Array 'a' mit 123Byte [] a = (...); für (int i = 0; i <a.länge; i ++) a [i] = 123;
(Bevorzugte) Methoden zur Verwendung der Standardbibliothek:
Arrays.Fill (a, (Byte) 123);
Kopieren Sie ein Array -Element in einem Bereich
Verwenden von Schleifen:
// 8 Elemente aus Array 'A' Start bei Offset 3 // an Array 'B' Start bei Offset 6, // Angenommen, 'A' und 'B' sind unterschiedliche ArraysByte [] a = (...);
(Bevorzugte) Methoden zur Verwendung der Standardbibliothek:
System.ArrayCopy (A, 3, B, 6, 8);
Größen Sie die Größe des Arrays
Verwenden Sie Schleifen (Skalierung):
// Array 'a' größer zu newlenbyte [] a = (...); byte [] b = new Byte [newlen]; für (int i = 0; i <a.länge; i ++) // steigt auf eine Länge von a b [i] = a [i]; a = b;
Verwenden Sie Schleifen (reduzieren Sie die Größe):
// Array 'a' kleiner zu newlenbyte [] a = (...); byte [] b = new Byte [newlen]; für (int i = 0; i <b.Length; i ++) // steigt bis Länge von B b [i] = a [i]; a = b;
(Bevorzugte) Methoden zur Verwendung der Standardbibliothek:
a = arrays.copyof (a, newlen);
4 Bytes in ein int packen
int packbigendian (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;}Int in 4 Bytes zersetzen
byte[] unpackBigEndian(int x) { return new byte[] { (byte)(x >>> 24), (byte)(x >>> 16), (byte)(x >>> 8), (byte)(x >>> 0) };} byte[] unpackLittleEndian(int x) { return new byte[] { (byte)(x >>> 0), (byte) (x >>> 8), (byte) (x >>> 16), (byte) (x >>> 24)};}Verwenden Sie immer den nicht signierten Rechtsverschiebungsoperator (>>>), um die Bits einzuwickeln. Verwenden Sie den arithmetischen Rechtsverschiebungsoperator nicht (>>).