En kort oversigt over bedste praksis for Java-kodning

baseret på kodningsstandarder fra Oracle, Google, Twitter og Spring Framework

Formålet med denne artikel er at give dig en hurtig oversigt over gør og må ikke med andre ord foretrække og undgå baseret på kodningsstandarder fra tech-giganter som Oracle, Google, Twitter og Spring Framework.

Du er måske eller måske ikke enig med nogle af de bedste fremgangsmåder, der er præsenteret her, og det er helt fint, så længe der er nogen kodningsstandard på plads.

Hvorfor kodningsstandarder i første omgang? Der er mange gode grunde, hvis du Google det, og jeg vil forlade dig med følgende illustration

Dokument for kodningsstandarder kan være langvarige og kedelige. Denne artikel kirsebær plukker bits og stykker fra kodningskonventioner fra Google, Oracle, Twitter og Spring og det er målet at give dig et let at følge og mindre kedeligt sæt praksis for at gøre din kode let at læse og vedligeholde.

Næsten altid vil du deltage i teams, der arbejder med eksisterende software, og der er en ret god chance for, at de fleste af forfatterne har forladt eller skiftet til forskellige projekter, hvilket efterlader dig strandet med dele af koden, der får dig til at stille spørgsmålstegn ved menneskeheden.

Lad os dykke ned i bedste praksis fra forskellige kodningsstandarder.

Java-kildefil

Følgende betragtes som bedste praksis, når det kommer til java-kildefiler:

  • Kildefilens længde er mindre end 2.000 kodelinjer
  • Kildefilen er organiseret med dokumentationskommentar, pakkedeklaration, efterfulgt af en klassekommentar, importeret grupperet (statisk sidst), klasse / interface signatur og så videre som vist nedenfor
pakke com.example.model;
/ **
 * Implementeringsfrit perspektiv, der skal læses af udviklere
 * der muligvis ikke nødvendigvis har kildekoden ved hånden
 *
 * @ forfatter x, y, z
 * @ dato
 * @version
 * @ophavsret
 *
 * /
import com.example.util.FileUtil;
/ *
 * Valgfri klassespecifik kommentar
 *
 * /
offentlig klasse SomeClass {
  // Statiske variabler i rækkefølge af synlighed
  offentlig statisk endelig heltal PUBLIC_COUNT = 1;
  statisk endelig heltal PROTECTED_COUNT = 1;
  privat statisk endelig heltal PRIVATE_COUNT = 1;
  // Forekomstvariabler i rækkefølge af synlighed
  offentlig streng navn;
  String postal-kode;
  privat streng adresse;
  // Konstruktør og overbelastet i rækkefølge
  public SomeClass () {}
  public SomeClass (strengnavn) {
    this.name = name;
  }
  // Metoder
  public String doSomethingUseful () {
    returnere "Noget nyttigt";
  }
  // getters, seters, equals, hashCode og toString i slutningen
}

Navngivning

Klasse- og interfacenavne er CamelCase, og det anbefales at bruge hele ordet og undgå akronymer / forkortelser. For eksempel klasse Raster eller klasse ImageSprite

  • Pakke - navngiver com.deepspace over com.deepSpace eller com.deep_space
  • Filnavne er CamelCase og slutter med .java, der matcher klassens navn. Der er en offentlig klasse pr. Fil med hver klasse på øverste niveau i sin fil
  • Metode - navne skal være verb i blandet tilfælde med hvert internt ord, der aktiveres for eksempel kørsel (); eller runFast ();
  • Konstanter - skal være med store bogstaver med “_”, der adskiller hvert ord for eksempel int MIN_WIDTH = 44; og int MAX_WIDTH = 99;
  • Variabel - et navn, der fortæller læseren af ​​programmet, hvad variablen repræsenterer, dvs. hvis du gemmer en testkvalitet, skal du vælge karakter kontra var1. Hold variablenavne korte, undgå at inkludere metadata.
// Foretrukne () - korte navne på variabler og beskriv, hvad det gemmer
int-skoleId;
int [] filteredSchoolIds;
int [] uniqueSchooldIds;
Kort  brugereById;
Strengværdi;
// Undgå (x) - For detaljeret variabel navngivning
int schoolIdentificationNumber;
int [] userProvidedSchoolIds;
int [] skoleIdsAfterRemoving Duplicates;
Kort  idToUserMap;
String valueString;

Husk - variabelnavn skal være kort og let fortælle læseren, hvilken værdi den repræsenterer. Brug din bedømmelse.

Foretrækker & undgå

Formatering og indrykning handler om at organisere din kode for at gøre det let at læse, og det inkluderer afstand, linjelængde, indpakning og pauser og så videre

  • Indrykning - Brug 2 eller 4 mellemrum og hold jævnhed
  • Linjelængde - Op til 70 til 120 tegn afhængigt af indflydelse på læsbarheden. Det er vigtigt at fjerne behovet for vandret rulning og placere linjepauser efter et komma og en operatør.

Metoder - Her er en oversigt over bedste praksis

// Foretrukne () Linjepauser er vilkårlige og brydes efter et komma.
Streng downloadAnInternet (Internet internet, rør rør,
    Blogosphere-blogs, Mængde  båndbredde) {
  tubes.download (internet);
}
// Undgå (x) Metode, der er vanskelig at diff, argumenterer for metodekroppen
Streng downloadAnInternet (Internet internet, rør rør,
    Blogosphere-blogs, Mængde  båndbredde) {
    tubes.download (internet);
}
// Foretrukne () Tilføj 8 (dobbelt på 2 eller 4) mellemrum til dybt indrykk
privat statisk synkroniseret horkingLongMethodName (int anArg,
        Objekt en andenArg, String endnuAnotherArg,
        Objekt og StillAnother) {
  ...
}
// Foretrukne () Nem scanning og ekstra søjleplads.
public String downloadAnInternet (
    Internet internet,
    Rør rør,
    Blogosphere-blogs,
    Mængde  båndbredde) {
  tubes.download (internet);
  ...
}
En enhedstest ville have fanget det

Hvis-kontroller - IMO, der skriver velformateret kode, gør det nemt at se typos og fejl på forfatteren og kodevurdererne, se nedenfor:

// Undgå (x) Du må ikke udelade {}
hvis (betingelse)
  udmelding;
// Undgå (x)
hvis (x <0) negativ (x);
// Undgå (x)
hvis (a == b && c == d) {
...
}
// Foretrækker ()
hvis ((a == b) && (c == d)) {
...
}
// Foretrækker ()
hvis (betingelse) {
  udsagn;
} andet hvis (betingelse) {
  udsagn;
} andet hvis (betingelse) {
  udsagn;
}
// Undgå (x)
if ((betingelse1 && betingelse2)
    || (betingelse3 && betingelse4)
    ||! (betingelse5 && betingelse6)) {// DÅRLIGE WRAPS
    gøre noget ved det(); // Gør DENNE LINJER LET AT MISSE
}
// Foretrækker ()
if ((betingelse1 && betingelse2)
        || (betingelse3 && betingelse4)
        ||! (betingelse5 && betingelse6)) {
    gøre noget ved det();
}

Ternary operator - Og nedenfor anbefales praksis

alpha = (aLongBooleanEpression)? beta: gamma;
alpha = (aLongBooleanEpression)? beta
        : gamma;
alpha = (aLongBooleanEpression)
        ? beta
        : gamma;

Skift - Når det drejer sig om at skifte, er det bedste praksis til

  • Har altid en standard sag, også uden kode
  • Brug / * falder gennem * / for at indikere, at kontrollen falder til næste tilfælde
switch (tilstand) {
  sag ABC:
    udsagn;
  / * falder igennem * /
  sag DEF:
    udsagn;
    pause;
  Standard:
    udsagn;
     pause;
}

Undtagelsesmeddelelser - Når du kaster en undtagelse her, er der eksempler på gode og dårligt indrykkede meddelelser.

// Undgå (x) - Ikke let at læse
kaste ny IllegalStateException ("Kunne ikke behandle anmodning" + request.getId ()
    + "for user" + user.getId () + "forespørgsel: '" + query.getText ()
    + "'");
// Foretrækker () - Temmelig lettere at læse
kaste ny IllegalStateException ("Kunne ikke behandle"
    + "anmodning" + anmodning.getId ()
    + "for bruger" + user.getId ()
    + "forespørgsel: '" + forespørgsel.getText () + "'");

Iteratorer og strømme - Strømme bliver mere almindelige, og til tider kan det være meget komplekst, derfor er det vigtigt at indrykkes for let at læse.

// Undgå (x) - Ikke let at læse
Iterable  modules = ImmutableList.  builder (). Tilføj (ny LifecycleModule ())
    .add (ny AppLauncherModule ()). addAll (application.getModules ()). build ();
// Foretrækker () - Temmelig lettere at læse
Iterable  modules = ImmutableList.  builder ()
    .add (ny LifecycleModule ())
    .add (ny AppLauncherModule ())
    .addAll (application.getModules ())
    .build ();
Bare følg en kodningsstandard - enhver virkelig

Erklæringer og opgaver - Der anbefales en erklæring pr. Linje, da den tilskynder til kommentarer som vist nedenfor.

// Foretrækker ()
int niveau; // indrykningsniveau
int størrelseMeter; // bordstørrelse
// Undgå (x) til fordel for ovenstående
int-niveau, størrelseMeter;
// Foretrukne () - Medtag enhed i variabelnavn eller -type
lang pollIntervalMs;
int fileSizeGb;
Mængde  filstørrelse;
// Undgå (x) blandingstyper
int foo, fooarray [];
// Undgå (x) - Må ikke adskilles med komma
Format.print (System.out, “fejl”), exit (1);
// Undgå (x) multiple tildeling
fooBar.fChar = barFoo.lchar = 'c';
// Undgå (x) indlejrede tildelinger i forsøg på at øge ydeevnen // eller gemme en linje. Jeg er skyldig i at gøre dette :(
d = (a = b + c) + r;
// Foretrækker () fremfor
a = b + c;
d = a + r;
// Foretrækker ()
String [] args
// Undgå (x)
Streng args []
// Foretrækker () Brug længe "L" i stedet for "l" for at undgå forvirring med 1
lang timeout = 3000000000L;
// Undgå (x) - Svært at fortælle sidste bogstav er l og ikke 1
lang timeout = 3000000000l;

Sæt erklæringer kun i begyndelsen af ​​blokke (En blok er kode omgivet af krøllede seler {og}). Vent ikke med at erklære variabler indtil deres første brug; det kan forvirre den uforsigtige programmerer og hæmme kodeportabilitet inden for omfanget.

// Foretrækker () at erklære i begyndelsen af ​​blokken.
public void doSomething () {
  int whatIRepresent; // Begyndelse af metodeblok
  hvis (betingelse) {
    int nogleFlag; // begyndelsen af ​​“hvis” -blok
    ...
  }
}

Det er også vigtigt at undgå lokale erklæringer, der skjuler erklæringer om de højere niveauer og er at undgå forvirring, som vist nedenfor

int tæller;
...
public void doSomething () {
  hvis (betingelse) {
    int tæller; // UNDGÅ!
    ...
  }
  ...
}

Mellemrum & linjepauser - Undgå fristelsen til at gemme 1-2 linjer med kode på bekostning af læsbarheden. Her er alle de bedste fremgangsmåder, når det kommer til afstand og blanke linjer (Et hvidt rum gør en forskel)

  • Én (1) blank linje mellem metoder og Spring-udviklere anbefaler to (2) blanke linjer efter konstruktører, statisk blok, felter og indre klasse
  • Space pad-operatører, dvs. brug int foo = a + b + 1; over int foo = a + b + 1;
  • Adskill alle binære operatører undtagen “.” Fra operander, der bruger et mellemrum
  • Åben stag "{" vises i slutningen af ​​den samme linje som erklæringserklæringen eller -metoden og lukningstroppen "}" starter en linje i sig selv indrykket
// Foretrukne () - Mellemrum efter "mens" og før "("
mens (sandt) {
  ...
}
// Undgå (x) - I modsætning til over intet mellemrum
mens (sandt) {
  ...
}
// Foretrukne () - Intet mellemrum mellem "doSomething" og "("
public void doSomething () {
  ...
}
// Undgå (x) - I modsætning til over afstand
public void doSomething () {
  ...
}
// Foretrukne () - Tilføj et mellemrum efter et argument
public void doSomething (int a, int b) {
  ...
}
// Foretrukne () - Mellemrum mellem operand og operatører (dvs. +, =)
a + = c + d;
a = (a + b) / (c * d);
mens (d ++ = s ++) {
  n ++;
}

Dokumentation og kommentarer

Det er værd at nævne, at næsten al kode ændrer sig i hele sin levetid, og at der vil være tidspunkter, hvor du eller nogen prøver at finde ud af, hvad en kompleks blok af kode, en metode eller en klasse er beregnet til at gøre, medmindre det er klart beskrevet. Virkeligheden er næsten altid som følger

Der er tidspunkter, hvor kommentaren til et komplekst stykke kode, metode, klasse ikke tilføjer nogen værdi eller tjener sit formål. Dette sker normalt, når man kommenterer for det.

Kommentarer skal bruges til at give oversigter over koden og give yderligere oplysninger, der ikke er let tilgængelige i selve koden. Lad os komme igang. Der er to typer kommentarer

Implementeringskommentarer - er beregnet til at kommentere kode eller kommentere om en bestemt implementering af koden.

Dokumentationskommentarer - er beregnet til at beskrive specifikationen af ​​koden fra et implementeringsfrit perspektiv, der skal læses af udviklere, som muligvis ikke nødvendigvis har kildekoden ved hånden.

Hyppigheden af ​​kommentarer afspejler undertiden dårlig kvalitet på koden. Når du føler dig tvunget til at tilføje en kommentar, kan du overveje at omskrive koden for at gøre den klarere.

Typer af implementeringskommentarer

Der er fire (4) typer implementeringskommentarer som vist nedenfor

  • Bloker kommentar - se eksempel nedenfor
  • Kommentar på en linje - når kommentaren ikke er længere end en linje
  • Efterfølgende kommentarer - Meget kort kommentar flyttet til højre ende
  • Slut på linjekommentaren - begynder en kommentar, der fortsætter til den nye linje. Det kan kommentere en komplet linje eller kun en delvis linje. Det bør ikke bruges på på hinanden følgende flere linjer til tekstkommentarer; det kan dog bruges i på hinanden følgende flere linjer til at kommentere kodesektioner.
// Bloker kommentar
/ *
 * Anvendelse: Giver beskrivelse af filer, metoder, datastrukturer
 * og algoritmer. Kan bruges i begyndelsen af ​​hver fil og
 * før hver metode. Bruges til lange kommentarer, der ikke passer til en
 * enkelt linje. 1 Blank linje for at fortsætte efter blokkommentaren.
 * /
// Kommentar med en linje
hvis (betingelse) {
 / * Håndter tilstanden. * /
  ...
}
// Efterfølgende kommentar
hvis (a == 2) {
 returnere SAND; /* særlig situation */
} andet {
 return isPrime (a); / * fungerer kun til ulige a * /
}
// Kommentar til slutningen af ​​linjen
hvis (foo> 1) {
  // Lav en dobbelt vip.
  ...
} andet {
  vende tilbage falsk; // Forklar hvorfor her.
}
// if (bjælke> 1) {
//
// // Lav en triple-flip.
// ...
//}
//andet
// returner falsk;

Dokumentationskommentarer (dvs. Javadoc)

Javadoc er et værktøj, der genererer HTML-dokumentation fra din java-kode ved hjælp af kommentarer, der begynder med / ** og slutter med * / - se Wikipedia for at få flere oplysninger om, hvordan Javadoc fungerer eller bare læse videre.

Her er et eksempel på Javadoc

/ **
 * Returnerer et billedeobjekt, der derefter kan males på skærmen.
 * URL-argumentet skal angive en absolut {@link URL}. Navnet
 * argument er en specifikator, der er i forhold til url-argumentet.
 * 

 * Denne metode vender altid straks tilbage, uanset om  * billedet findes. Når denne applet prøver at tegne billedet på  * på skærmen indlæses dataene. Grafik primitiver  * der tegner billedet vil gradvis male på skærmen.  *  * @param url en absolut URL, der giver billedets baseplacering  * @param navngive placeringen af ​​billedet i forhold til url-argumentet  * @ Gentag billedet på den angivne URL  * @see billede  * /  public Image getImage (URL-url, strengnavn) {         prøve {             return getImage (ny URL (url, navn));         } fangst (MalformedURLException e) {             returnere null;         }  }

Og ovenstående ville resultere i en HTML som følger, når javadoc køres mod koden, der har ovenstående

Se her for mere

Her er nogle nøglemærker, som du kan bruge til at forbedre kvaliteten af ​​den genererede java-dokumentation.

@author => @author Raf
@code => {@code A  C}
@deprecated => @deprecated afskrivningsmeddelelse
@exception => @exception IOException kastet hvornår
@link => {@link package.class # medlemsetiket}
@param => @param parameter-navn beskrivelse
@return => Hvad metoden vender tilbage
@see => @see "streng" ELLER @ se  
@since => At indikere versionen, når en offentligt tilgængelig metode tilføjes

For en komplet liste og mere detaljeret beskrivelse se her

Twitter's kodningsstandard fraråder brug af @author-tag

Kode kan skifte hænder adskillige gange i sin levetid, og ofte er den oprindelige forfatter af en kildefil irrelevant efter flere iterationer. Vi synes, det er bedre at stole på forpligtelseshistorik og OWNERS-filer for at bestemme ejerskabet af et kodenavn.

Følgende er eksempler på, hvordan du kan skrive en dokumentationskommentar, der er indsigtsfuld som beskrevet i Twitter's kodningsstandard

// Dårligt.
// - Dokumentet fortæller intet, at metodedeklarationen ikke gjorde det.
// - Dette er 'filler doc'. Det ville bestå stilkontrol, men
hjælper ikke nogen.
/ **
 * Opdeler en streng.
 *
 * @param s En streng.
 * @ return En liste over strenge.
 * /
Liste  delt (streng);
// Bedre.
// - Vi ved, hvad metoden splitter på.
// - Stadig noget udefineret opførsel.
/ **
 * Opdeler en streng på hvidafstand.
 *
 * @param s Den streng, der skal opdeles. En {@code null} streng behandles som en tom streng.
 * @ return En liste over de dele, der er afgrænset med det hvide rum, af input.
 * /
Liste  delt (streng);
// Store.
// - Dækker endnu en kantkant.
/ **
 * Opdeler en streng på hvidafstand. Gentagne hvidafstandstegn
 * er kollapset.
 *
 * @param s Den streng, der skal opdeles. En {@code null} streng behandles som en tom streng.
 * @ return En liste over de dele, der er afgrænset med det hvide rum, af input.
 * /
Liste  delt (streng);

Det er vigtigt at være professionel, når det kommer til at skrive kommentarer

// Undgå (x)
// Jeg hader xml / sæbe så meget, hvorfor kan det ikke gøre dette for mig !?
prøve {
  userId = Integer.parseInt (xml.getField ("id"));
} fangst (NumberFormatException e) {
  ...
}
// Foretrækker ()
// TODO (Jim): Valg af feltfelt væk i et bibliotek.
prøve {
  userId = Integer.parseInt (xml.getField ("id"));
} fangst (NumberFormatException e) {
  ...
}

Og det er vigtigt at huske på ikke at dokumentere tilsidesat metode, medmindre implementeringen er ændret.

Og her er et par flere punkter, du skal huske på

  • Undgå import af jokertegn - som beskrevet i Twitter's kodningsstandarder gør det kilden til klasse mindre klar. Jeg arbejder i et team med en blanding af Eclipse- og IntelliJ-brugere, og jeg fandt ud af, at Eclipse fjerner jokertimport og IntelliJ introducerer den. Der er sandsynligvis en mulighed for at slå den fra, ville bare påpege standard for de to.
  • Brug altid @Override-kommentar, når du tilsidesætter
  • Tilskynde til brug af @Nullable, når et felt eller metode returnerer nul
  • Brug specielle kommentarer til fremtidig arbejde, og glem ikke at give en henvisning til dig selv, så andre ved, hvem de skal stille deres Y-spørgsmål i stedet for at gætte, fjerne det eller kontrollere git-skylden for at finde, hvem der har tilføjet det. Nogle IDE'er som Eclipse og IntelliJ hjælper også med at liste disse for nem adgang såvel som en påmindelse.
// FIXME (Raf): En meddelelse, der kan handles, beskriver, hvad der skal gøres
// TODO (Raf): En handling, der kan bruges, beskriver, hvad der skal gøres

Slutspilet er at skrive kode, der gør livet for fremtidige forfattere og vedligeholdere let.

Slutspil

Andre relevante læsestoffer

En oversigt over relevante artikler, der er relevante for at skrive kode, der er ren, velstruktureret, let at læse og vedligeholde. Hvis du ønsker at læse mere, kan du bestemt anbefale følgende

og en anden god liste over tip til skrivning af ren kode