Un scurt rezumat al celor mai bune practici de codare Java

bazat pe standardele de codare de către Oracle, Google, Twitter și Spring Framework

Obiectivul acestui articol este să vă oferim un scurt rezumat al lucrurilor și, cu alte cuvinte, nu preferați și evitați să se bazeze pe standardele de codificare ale gigantilor tehnologici precum Oracle, Google, Twitter și Spring Framework.

S-ar putea să fiți sau nu de acord cu unele dintre cele mai bune practici prezentate aici și care sunt absolut bune atât timp cât există un standard de codare în vigoare.

De ce standardele de codare în primul rând? Există multe motive bune dacă Google o Google și vă voi lăsa cu următoarea ilustrație

Documentele standardelor de codare pot fi îndelungate și plictisitoare. Acest articol cireșește bucăți și bucăți din convențiile de codare de Google, Oracle, Twitter și Spring și obiectivul este să vă ofere un set de practici ușor de urmărit și mai puțin plictisitor pentru a vă face ușor de citit și de întreținut.

Aproape întotdeauna vă veți alătura echipelor care lucrează la software-ul existent și există o șansă destul de bună ca majoritatea autorilor să plece sau să treacă la diferite proiecte, lăsându-vă înșelat cu porțiuni de cod care vă determină să puneți la îndoială umanitatea.

Să ne scufundăm în cele mai bune practici din diferite standarde de codificare.

Fișier sursă Java

Următoarele lucruri sunt considerate cele mai bune practici atunci când vine vorba de fișiere sursă java:

  • Lungimea fișierului sursă este mai mică de 2.000 de linii de cod
  • Fișierul sursă este organizat cu comentariu de documentație, declarație de pachet, urmat de un comentariu de clasă, importuri grupate (ultima statică), semnătura clasei / interfeței, etc. așa cum se arată mai jos
pachet com.example.model;
/ **
 * Perspectivă fără implementare pentru a fi citită de dezvoltatori
 * care ar putea să nu aibă neapărat codul sursă la îndemână
 *
 * @autor x, y, z
 * @Data
 * @versiune
 * @copyright
 *
 * /
import com.example.util.FileUtil;
/ *
 * Comentariu opțional specific clasei
 *
 * /
public class SomeClass {
  // Variabilele statice în ordinea vizibilității
  public static final Integer PUBLIC_COUNT = 1;
  static final Integer PROTECTED_COUNT = 1;
  private static final Inter PRIVATE_COUNT = 1;
  // Variabilele de instanță în ordinea vizibilității
  nume public String;
  String postalCode;
  adresă privată String;
  // Constructor și supraîncărcat în ordine secvențială
  public SomeClass () {}
  public SomeClass (String name) {
    this.name = nume;
  }
  // Metode
  public String doSomethingUseful () {
    returnați „Ceva util”;
  }
  // getters, setters, egal, hashCode și toString la final
}

Denumire

Numele clasei și interfeței sunt CamelCase și se recomandă utilizarea întregului cuvânt și evitarea acronimelor / prescurtărilor. De exemplu, clasa Raster sau clasa ImageSprite

  • Pachet - nume com.deepspace peste com.deepSpace sau com.deep_space
  • File - numele sunt CamelCase și se termină cu .java care se potrivește cu numele clasei. Există o clasă publică per fișier cu fiecare clasă de nivel superior în fișierul său
  • Metodă - numele ar trebui să fie verbe în cazuri mixte cu fiecare cuvânt intern majusculat, de exemplu run (); sau runFast ();
  • Constante - ar trebui să fie majuscule cu „_” care separă fiecare cuvânt, de exemplu int MIN_WIDTH = 44; și int MAX_WIDTH = 99;
  • Variabilă - un nume care spune cititorului programului ce reprezintă variabila, adică dacă stocați o notă de testare, atunci alegeți gradul vs var1. Mențineți numele de variabile scurte, pentru a evita metadatele.
// Preferă () - nume variabile scurte și descrieți ce stochează
int schoolId;
int [] filteredSchoolIds;
int [] uniqueSchooldIds;
Harta  usersById;
Valoarea șirului;
// Evitați (x) - Denumirea prea detaliată a variabilelor
int școalăIdentificareNumăr;
int [] userProvidedSchoolIds;
int [] școalăIdsAfterRemovingDuplicates;
Harta  idToUserMap;
String valueString;

Amintiți-vă - numele variabilei ar trebui să fie scurt și spuneți cu ușurință cititorului ce valoare reprezintă. Folosește-ți judecata.

Preferați și evitați

Formatarea și indentarea se referă la organizarea codului dvs. pentru a fi ușor de citit și include spațiere, lungimea liniei, înfășurări și pauze etc.

  • Indentare - Utilizați 2 sau 4 spații și rămâneți consecvent
  • Lungimea liniei - Până la 70 până la 120 de caractere, în funcție de afectarea lizibilității. Este important să eliminăm necesitatea defilării orizontale și a locurilor pauzelor după o virgulă și un operator.

Metode - Iată o listă a celor mai bune practici

// Preferă () Pauzele de linie sunt arbitrare și se rup după virgulă.
Descărcarea șirurilorAnInternet (Internet Internet, Tuburi tuburi,
    Bloguri de blogosferă, cantitate  lățime de bandă) {
  tubes.download (internet);
}
// Evitați (x) Metoda argilă greu de difuzat față de corpul metodei
Descărcarea șirurilorAnInternet (Internet Internet, Tuburi tuburi,
    Bloguri de blogosferă, cantitate  lățime de bandă) {
    tubes.download (internet);
}
// Preferă () Adăugați 8 (dubla de 2 sau 4) spații pentru indentare profundă
horking sincronizat privat staticLongMethodName (int anArg,
        Obiectați un altArg, String încăAnotherArg,
        Obiect și StillAnother) {
  ...
}
// Preferă () Scanare ușoară și spațiu suplimentar pentru coloane.
public String downloadAnInternet (
    Internet internet,
    Tuburi tuburi,
    Blogosfera blogosfera,
    Suma  lățime de bandă) {
  tubes.download (internet);
  ...
}
Un test unitar ar fi prins asta

If-checks - IMO scrie cod bine formatat face ușor de identificat dactilografiile și erorile pentru autor și recenzorii de coduri, a se vedea mai jos:

// Evitați (x) Nu omiteți {}
daca (conditie)
  afirmație;
// Evitați (x)
dacă (x <0) negativ (x);
// Evitați (x)
if (a == b && c == d) {
...
}
// Preferă ()
if ((a == b) && (c == d)) {
...
}
// Preferă ()
if (stare) {
  declarații;
} else if (condiție) {
  declarații;
} else if (condiție) {
  declarații;
}
// Evitați (x)
if ((condiție1 && condiție2)
    || (condiție3 && condiție4)
    ||! (condiție 5 &&6 condiție6)) {// BAD WRAPS
    Fă ceva în privința asta(); // FACI ACEASTA LINIE UȘOR DE LUAT
}
// Preferă ()
if ((condiție1 && condiție2)
        || (condiție3 && condiție4)
        ||! (condiție5 &&66)) {
    Fă ceva în privința asta();
}

Operator ternar - Și mai jos sunt practici recomandate

alpha = (aLongBooleanExpression)? beta: gamma;
alpha = (aLongBooleanExpression)? beta
        : gama;
alpha = (aLongBooleanExpression)
        ? beta
        : gama;

Comutați - când vine vorba de comutare, este cea mai bună practică

  • Aveți întotdeauna un caz implicit chiar și fără cod
  • Utilizați / * cad prin * / pentru a indica căderea controlului în cazul următor
comutator (stare) {
  caz ABC:
    declarații;
  / * se încadrează prin * /
  caz DEF:
    declarații;
    pauză;
  Mod implicit:
    declarații;
     pauză;
}

Mesaje de excepție - Când aruncați o excepție, aici sunt mostre de mesaje bune și slab indentate.

// Evitați (x) - Nu este ușor de citit
throw new IllegalStateException ("Nu a reușit procesarea cererii" + request.getId ()
    + "pentru utilizator" + user.getId () + "interogare: '" + query.getText ()
    + "'");
// Preferă () - Destul de ușor de citit
aruncă noul IllegalStateException („Nu a reușit procesarea”
    + "cerere" + request.getId ()
    + "pentru utilizator" + user.getId ()
    + "interogare: '" + query.getText () + "'");

Iteratori și fluxuri - Streamurile devin mai frecvente și, uneori, pot fi foarte complexe, prin urmare, este important să indentăm pentru a fi ușor de citit.

// Evitați (x) - Nu este ușor de citit
Iterable  modules = ImmutableList.  builder (). Add (new LifecycleModule ())
    .add (noul AppLauncherModule ()). addAll (application.getModules ()). build ();
// Preferă () - Destul de ușor de citit
Iterable  modules = ImmutableList.  builder ()
    .add (noul LifecycleModule ())
    .add (noul AppLauncherModule ())
    .addAll (application.getModules ())
    .construi();
Trebuie doar să urmați un standard de codare - oricare este cu adevărat

Declarații și misiuni - Se recomandă o declarație pe fiecare linie, deoarece încurajează comentariile așa cum se arată mai jos.

// Preferă ()
nivel int; // nivelul de indentare
dimensiune intMeter; // dimensiunea mesei
// Evitați (x) în favoarea celor de mai sus
nivel int, sizeMeter;
// Preferă () - Includeți unitatea în numele sau tipul variabilei
lung pollIntervalMs;
fișier intSizeGb;
Suma  dimensiune fișier;
// Evitați (x) tipurile de amestecare
int foo, fooarray [];
// Evitați (x) - Nu vă separați cu virgule
Format.print (System.out, „eroare”), ieșiți (1);
// Evitați (x) o alocare multiplă
fooBar.fChar = barFoo.lchar = 'c';
// Evitați (x) atribuții încorporate în încercarea de a crește performanța // sau de a salva o linie. Sunt vinovat că am făcut acest lucru :(
d = (a = b + c) + r;
// Preferă () mai sus
a = b + c;
d = a + r;
// Preferă ()
String [] args
// Evitați (x)
Corduri argint []
// Preferă () Folosește îndelung „L” în loc de „l” pentru a evita confuzia cu 1
timp lung = 3000000000L;
// Evitați (x) - Ultima scrisoare este greu de spus și nu 1
timeout lung = 3000000000l;

Puneți declarații doar la începutul blocurilor (Un bloc este cod înconjurat de bretele cretate {și}). Nu așteptați să declarați variabile până la prima utilizare; acesta poate confunda programatorul nedorit și poate împiedica portabilitatea codului în sfera de aplicare.

// Preferă () să declare la începutul blocului.
public void doSomething () {
  intradirecvent; // începutul blocului de metode
  if (stare) {
    int someFlag; // începutul blocului „if”
    ...
  }
}

De asemenea, este important să se evite declarațiile locale care ascund declarațiile de niveluri superioare și să se evite confuziile așa cum se arată mai jos

număr de int;
...
public void doSomething () {
  if (stare) {
    număr de int; // EVITA!
    ...
  }
  ...
}

Spațiu și pauze de linie - Evitați tentația de a salva 1-2 linii de cod în detrimentul lizibilității. Iată toate cele mai bune practici atunci când vine vorba de spațiere și linii goale (Un spațiu alb face diferența)

  • Una (1) linie goală între metode și dezvoltatorii Spring recomandă două (2) linii goale după constructori, bloc static, câmpuri și clasă interioară
  • Operatori de paduri spațiale, adică utilizați int foo = a + b + 1; peste int foo = a + b + 1;
  • Separați toți operatorii binari, cu excepția „.” De operanzi folosind un spațiu
  • Brațul deschis „{” apare la sfârșitul aceleiași linii cu declarația sau metoda declarației, iar bretonul de închidere „}” începe o linie indentificată
// Preferă () - Spațiu după „timp” și înainte ”(„
while (true) {
  ...
}
// Evitați (x) - Spre deosebire de mai sus niciun spațiu
while (true) {
  ...
}
// Preferă () - Fără spațiu între „doSomething” și „(„
public void doSomething () {
  ...
}
// Evitați (x) - Spre deosebire de spațiul de mai sus
public void doSomething () {
  ...
}
// Preferă () - Adaugă un spațiu după un argument
public void doSomething (int a, int b) {
  ...
}
// Preferă () - Spațiu între operand și operatori (adică +, =)
a + = c + d;
a = (a + b) / (c * d);
while (d ++ = s ++) {
  n ++;
}

Documentare și comentarii

Merită menționat că aproape toate codurile se schimbă pe parcursul întregii sale vieți și vor exista momente în care tu sau cineva încearcă să descoperi ce este un bloc complex de cod, o metodă sau o clasă intenționată să facă decât dacă este descris în mod clar. Realitatea este aproape întotdeauna așa cum urmează

Există momente în care comentariul asupra unei bucăți complexe de cod, metodă, clasă nu adaugă nicio valoare sau nu își servește scopul. Acest lucru se întâmplă de obicei atunci când comentați de dragul lui.

Comentariile trebuie utilizate pentru a oferi prezentări generale ale codului și pentru a oferi informații suplimentare care nu sunt ușor disponibile în cod. Să începem. Există două tipuri de comentarii

Comentarii de implementare - sunt menite să comenteze codul sau să comenteze o anumită implementare a codului.

Comentariile documentației - sunt destinate să descrie specificația codului dintr-o perspectivă fără implementare, pe care să o citească dezvoltatorii care s-ar putea să nu aibă neapărat codul sursă la îndemână.

Frecvența comentariilor reflectă uneori calitatea slabă a codului. Când vă simțiți obligat să adăugați un comentariu, luați în considerare rescrierea codului pentru a-l face mai clar.

Tipuri de comentarii de implementare

Există patru (4) tipuri de comentarii de implementare, după cum se arată mai jos

  • Comentare blocare - vezi exemplul de mai jos
  • Comentariu cu o singură linie - când comentariul nu este mai lung decât o linie
  • Comentarii de urmărire - Comentariul foarte scurt a fost mutat la capătul drept
  • Comentariu final de linie - începe un comentariu care continuă către linia nouă. Poate comenta o linie completă sau doar o linie parțială. Nu trebuie utilizat pe mai multe linii consecutive pentru comentarii text; cu toate acestea, poate fi utilizat în mai multe linii consecutive pentru comentarea secțiunilor de cod.
// Blocare comentariu
/ *
 * Utilizare: oferă descrierea fișierelor, metodelor, structurilor de date
 * și algoritmi. Poate fi utilizat la începutul fiecărui fișier și
 * înainte de fiecare metodă. Folosit pentru comentarii lungi care nu se potrivesc cu
 * o singura linie. 1 Linie goală pentru a continua după comentariul blocului.
 * /
// Comentariu cu o singură linie
if (stare) {
 / * Gestionează starea. * /
  ...
}
// Comentariu de urmărire
if (a == 2) {
 returna ADEVĂRAT; /* caz special */
} altfel {
 returnarea estePrime (a); / * funcționează doar pentru un impar * /
}
// Comentariu final de linie
if (foo> 1) {
  // Faceți un dublu flip.
  ...
} altfel {
  returnare falsă; // Explicați de ce aici.
}
// if (bar> 1) {
//
// // Faceți un triplu-flip.
// ...
//}
// altceva
// returnare falsă;

Comentarii privind documentația (adică Javadoc)

Javadoc este un instrument care generează documentație HTML formând codul dvs. java folosind comentariile care încep cu / ** și se termină cu * / - consultați Wikipedia pentru mai multe detalii despre modul în care funcționează Javadoc sau pur și simplu citiți.

Iată un exemplu de Javadoc

/ **
 * Returnează un obiect Image care poate fi apoi vopsit pe ecran.
 * Argumentul url trebuie să specifice o {@link URL} absolută. Numele
 * argument este un specificator relativ la argumentul url.
 * 

 * Această metodă întoarce întotdeauna imediat, indiferent dacă este sau nu  * imaginea există. Când această applet încearcă să atragă imaginea  * ecranul, datele vor fi încărcate. Primitivele grafice  * care desenează imaginea va picta treptat pe ecran.  *  * @param url o adresă URL absolută care oferă locația de bază a imaginii  * @param numele locației imaginii, în raport cu argumentul url  * @reiați imaginea la adresa URL specificată  * @see Image  * /  public Image getImage (URL adresă, nume șir) {         încerca {             return getImage (URL nou (URL, nume));         } prindere (MalformedURLException e) {             returnare nulă;         }  }

Iar cele de mai sus ar rezulta într-un HTML, după cum urmează, când javadoc este rulat împotriva codului care are mai sus

Vezi aici pentru mai multe

Iată câteva etichete cheie pe care le puteți utiliza pentru a îmbunătăți calitatea documentației java generate.

@author => @author Raf
@code => {@code A  C}
@deprecated => @deprecated-deprecation-message
@exception => @exception IOException aruncat când
@link => {@link package.class # label label}
@param => descrierea numelui parametrului @param
@return => Ce returnează metoda
@see => @see "string" SAU @see  
@since => Pentru a indica versiunea când se adaugă o metodă accesibilă publicului

Pentru o listare completă și o descriere mai detaliată, consultați aici

Standardul de codare al Twitter recomandă utilizarea etichetei @author

Codul poate schimba mâinile de nenumărate ori în timpul vieții sale și destul de des autorul original al fișierului sursă nu are relevanță după mai multe iterații. Considerăm că este mai bine să avem încredere în istoricul angajamentelor și în fișierele OWNERS pentru a determina proprietatea asupra unui corp de cod.

Vă prezentăm în continuare exemple despre cum ați putea scrie un comentariu de documentare care este înțeles, așa cum este descris în standardul de codare al Twitter

// Rău.
// - Documentul nu spune nimic că declarația de metodă nu a făcut-o.
// - Acesta este „documentul de umplere”. Ar trece verificări de stil, dar
nu ajută pe nimeni.
/ **
 * Divizează un șir.
 *
 * @param s Un șir.
 * @return O listă de șiruri.
 * /
Listă  split (String s);
// Mai bine.
// - Știm cu ce se desparte metoda.
// - Încă un comportament nedefinit.
/ **
 * Divizează un șir în spațiul alb.
 *
 * @param s Șirul de divizat. Un șir {@code null} este tratat ca un șir gol.
 * @return O listă a părților de intrare delimitate în spațiul alb.
 * /
Listă  split (String s);
// Grozav.
// - Acoperă încă o carcasă marginală.
/ **
 * Divizează un șir în spațiul alb. Caractere repetate din spațiul alb
 * sunt prăbușiți.
 *
 * @param s Șirul de divizat. Un șir {@code null} este tratat ca un șir gol.
 * @return O listă a părților de intrare delimitate în spațiul alb.
 * /
Listă  split (String s);

Este important să fii profesionist când vine vorba de a scrie comentarii

// Evitați (x)
// Urăsc atât de mult xml / soap, de ce nu poate face asta pentru mine !?
încerca {
  userId = Integer.parseInt (xml.getField ("id"));
} captură (NumberFormatException e) {
  ...
}
// Preferă ()
// TODO (Jim): validarea câmpului departe într-o bibliotecă.
încerca {
  userId = Integer.parseInt (xml.getField ("id"));
} captură (NumberFormatException e) {
  ...
}

Și este important să țineți cont de a nu documenta metoda suprasolicitată decât dacă implementarea sa schimbat.

Și aici mai sunt câteva puncte de reținut

  • Evitați importurile de wildcard - așa cum este descris în standardele de codare ale Twitter, această sursă este mai puțin clară. Lucrez în echipă cu un amestec de utilizatori Eclipse și IntelliJ și am aflat că Eclipse elimină importurile de wildcard și IntelliJ îl introduce. Probabil că există o opțiune pentru a o opri, am vrut doar să subliniez implicit pentru cei doi.
  • Utilizați întotdeauna adnotarea @Override atunci când treceți peste suprasolicitare
  • Încurajați utilizarea @Nullable atunci când un câmp sau o metodă revine nul
  • Utilizați comentarii speciale pentru lucrările viitoare și nu uitați să vă lăsați o referință pentru dvs., astfel încât alții știu cine să-și pună întrebarea Y în loc să ghicească, să o înlăture sau să verifice vina git pentru a găsi cine a adăugat-o. Unele IDE precum Eclipse și IntelliJ ajută la listarea acestora pentru un acces ușor, precum și un memento.
// FIXME (Raf): Un mesaj acționat descrie ce trebuie făcut
// TODO (Raf): Un mesaj acționat descrie ce trebuie făcut

Jocul final este acela de a scrie cod care să faciliteze viața viitorilor autori și mentenanți.

Jocul final

Alte materiale de citire relevante

O listă de articole relevante relevante pentru scrierea codului care este curat, bine structurat, ușor de citit și de întreținut. Dacă doriți să citiți mai multe, recomandă cu siguranță următoarele

și o altă listă bună de sfaturi pentru scrierea codului curat