En kort sammanfattning av bästa metoder för Java-kodning

baserat på kodningsstandarder av Oracle, Google, Twitter och Spring Framework

Syftet med denna artikel är att ge dig en snabb sammanfattning av gör och gör med andra ord föredrar och undviker baserat på kodningsstandarder från tekniska jättar som Oracle, Google, Twitter och Spring Framework.

Du kanske eller kanske inte håller med några av de bästa metoderna som presenteras här, och det är helt bra så länge det finns någon kodningsstandard på plats.

Varför kodningsstandarder i första hand? Det finns många goda skäl om du Google det och jag kommer att lämna dig följande illustration

Kodningsstandarddokumentet kan vara långt och tråkigt. Denna artikel körsbär plockar bitar och bitar från kodningskonventioner av Google, Oracle, Twitter och Spring och det är målet att ge dig en lätt att följa och mindre tråkiga uppsättningar för att göra din kod lätt att läsa och underhålla.

Nästan alltid kommer du att gå med i team som arbetar med befintlig programvara och det finns en ganska god chans att de flesta av författarna har lämnat eller bytt till olika projekt, vilket lämnar dig strandsatta med delar av kod som får dig att ifrågasätta mänskligheten.

Låt oss dyka in i bästa praxis från olika kodningsstandarder.

Java-källfil

Följande betraktas som bästa metoder när det gäller java-källfiler:

  • Källfilens längd är lägre än 2 000 kodrader
  • Källfilen är organiserad med dokumentationskommentar, paketdeklaration, följt av en klasskommentar, importerad gruppering (statisk sist), klass / gränssnittssignatur och så vidare som visas nedan
paket com.example.model;
/ **
 * Implementeringsfritt perspektiv som ska läsas av utvecklare
 * som kanske inte nödvändigtvis har källkoden till hands
 *
 * @ författare x, y, z
 * @datum
 * @version
 * @upphovsrätt
 *
 * /
import com.example.util.FileUtil;
/ *
 * Valfri klassspecifik kommentar
 *
 * /
public class SomeClass {
  // Statiska variabler i synbarhetsordning
  offentligt statiskt slutligt heltal PUBLIC_COUNT = 1;
  statisk slutligt heltal PROTECTED_COUNT = 1;
  privat statisk slutlig heltal PRIVATE_COUNT = 1;
  // Instansvariabler i synbarhetsordning
  offentligt strängnamn;
  String postal code;
  privat strängadress;
  // Konstruktör och överbelastad i sekvensordning
  public SomeClass () {}
  public SomeClass (String name) {
    this.name = name;
  }
  // Metoder
  public String doSomethingUseful () {
    returnera "Något användbart";
  }
  // getters, setters, equals, hashCode och toString i slutet
}

Namngivning

Klass- och gränssnittsnamn är CamelCase och det rekommenderas att använda hela ordet och undvika förkortningar / förkortningar. Till exempel klass Raster eller klass ImageSprite

  • Paket - namnger com.deepspace över com.deepSpace eller com.deep_space
  • Filnamn är CamelCase och slutar med .java som matchar klassnamnet. Det finns en offentlig klass per fil med varje toppnivå i sin fil
  • Metod - namn ska vara verb i blandade fall med varje internt ord som aktiveras till exempel kör (); eller runFast ();
  • Konstanter - bör vara med stora bokstäver med “_” som skiljer varje ord till exempel int MIN_WIDTH = 44; och int MAX_WIDTH = 99;
  • Variabel - ett namn som berättar programmets läsare vad variabeln representerar, dvs om du lagrar en testbetyg, välj sedan betyg kontra var1. Håll variabelnamn korta och undvik att inkludera metadata.
// Föredrag () - variabla namn kort och beskriv vad den lagrar
int skolskola;
int [] filteredSchoolIds;
int [] uniqueSchooldIds;
Karta  användareById;
Strängvärde;
// Undvik (x) - För detaljerad namngivning av variabler
int schoolIdentificationNumber;
int [] userProvidedSchoolIds;
int [] schoolIdsAfterRemovingDuplicates;
Karta  idToUserMap;
Strängvärde Sträng;

Kom ihåg - variabelns namn ska vara kort och enkelt säga läsaren vilket värde den representerar. Använd din bedömning.

Föredrar & undviker

Formatering och intryck handlar om att organisera din kod för att göra det enkelt att läsa, och det inkluderar avstånd, linjelängd, omslag och pauser och så vidare

  • Indragning - Använd 2 eller 4 utrymmen och håll dig konsekvent
  • Linjelängd - Upp till 70 till 120 tecken beroende på påverkan på läsbarheten. Det är viktigt att eliminera behovet av horisontell rullning och placera linjeavbrott efter komma och operatör.

Metoder - Här är en lista över bästa metoder

// Föredrar () Linjeavbrott är godtyckliga och bryter efter komma.
SträngnedladdningAnInternet (Internetinternet, Rör,
    Bloggosfärsbloggar, belopp  bandbredd) {
  tubes.download (Internet);
}
// Undvik (x) Metod som är svår att diff diff argumentera för metodkroppen
SträngnedladdningAnInternet (Internetinternet, Rör,
    Bloggosfärsbloggar, belopp  bandbredd) {
    tubes.download (Internet);
}
// Föredrar () Lägg till 8 (dubbel av 2 eller 4) utrymmen för djup intryck
privat statisk synkroniserad horkingLongMethodName (int anArg,
        Objekta en annanArg, String yetAnotherArg,
        Object andStillAnother) {
  ...
}
// Föredrag () Enkel skanning och extra kolumnutrymme.
public String downloadAnInternet (
    Internet internet,
    Rör,
    Bloggosfärsbloggar,
    Belopp  bandbredd) {
  tubes.download (Internet);
  ...
}
Ett enhetstest skulle ha fångat det

Om-kontroller - IMO skriver välformaterad kod gör det enkelt att upptäcka skrivfel och fel för författaren och kodgranskarna, se nedan:

// Undvik (x) Utelämna inte {}
om (villkor)
  påstående;
// Undvik (x)
om (x <0) negativt (x);
// Undvik (x)
if (a == b && c == d) {
...
}
// Föredrar ()
om ((a == b) && (c == d)) {
...
}
// Föredrar ()
if (villkor) {
  uttalanden;
} annat om (villkor) {
  uttalanden;
} annat om (villkor) {
  uttalanden;
}
// Undvik (x)
if ((villkor1 && villkor2)
    || (villkor3 && villkor4)
    ||! (villkor5 && villkor6)) {// BAD WRAPS
    gör något åt ​​det(); // GÖR DEN här LINJEN LÄTT ATT MISSNA
}
// Föredrar ()
if ((villkor1 && villkor2)
        || (villkor3 && villkor4)
        ||! (villkor5 && villkor6)) {
    gör något åt ​​det();
}

Ternary operator - Och nedan rekommenderas metoder

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

Byt - När det gäller att byta är det bästa praxis

  • Ha alltid ett standardfall även utan kod
  • Använd / * faller genom * / för att indikera att kontrollen faller till nästa fall
switch (villkor) {
  fall ABC:
    uttalanden;
  / * faller genom * /
  fall DEF:
    uttalanden;
    ha sönder;
  standard:
    uttalanden;
     ha sönder;
}

Undantagsmeddelanden - När du kastar ett undantag här är exempel på bra och dåligt intryckta meddelanden.

// Undvik (x) - Inte lätt att läsa
kasta ny IllegalStateException ("Det gick inte att behandla begäran" + request.getId ()
    + "för användare" + user.getId () + "fråga: '" + fråga.getText ()
    + "'");
// Föredrar () - Ganska lättare att läsa
kasta ny IllegalStateException ("Det gick inte att behandla"
    + "begäran" + begäran.getId ()
    + "för användare" + user.getId ()
    + "fråga: '" + fråga.getText () + "'");

Iteratorer och strömmar - Strömmar blir allt vanligare och ibland kan det vara väldigt komplicerat, det är viktigt att strecksats för lättläsning.

// Undvik (x) - Inte lätt att läsa
Iterable  modules = ImmutableList.  builder (). Lägg till (ny LifecycleModule ())
    .add (ny AppLauncherModule ()). addAll (application.getModules ()). build ();
// Föredrar () - Ganska lättare att läsa
Iterable  modules = ImmutableList.  builder ()
    .add (ny LifecycleModule ())
    .add (ny AppLauncherModule ())
    .addAll (application.getModules ())
    .bygga();
Följ bara en kodningsstandard - vilken som helst

Förklaringar och uppdrag - En rekommendation per rad rekommenderas eftersom den uppmuntrar kommentarer som visas nedan.

// Föredrar ()
int-nivå; // indragningsnivå
int storlekMeter; // bordets storlek
// Undvik (x) till förmån för ovan
int-nivå, storlekMeter;
// Föredrag () - Inkludera enhet i variabelnamn eller typ
long pollIntervalMs;
int fileSizeGb;
Mängd  filstorlek;
// Undvik (x) blandningstyper
int foo, fooarray [];
// Undvik (x) - Separera inte med komma
Format.print (System.out, “error”), exit (1);
// Undvik (x) flera tilldelningar
fooBar.fChar = barFoo.lchar = 'c';
// Undvik (x) inbäddade tilldelningar i försök att öka prestanda // eller spara en rad. Jag är skyldig till att göra detta :(
d = (a = b + c) + r;
// Föredrar () ovan
a = b + c;
d = a + r;
// Föredrar ()
String [] args
// Undvik (x)
String args []
// Föredrar () Använd länge "L" istället för "l" för att undvika förvirring med 1
lång timeout = 3000000000L;
// Undvik (x) - Svårt att säga sista bokstaven är l och inte 1
lång timeout = 3000000000l;

Sätt deklarationer bara i början av block (Ett block är kod omgiven av lockiga hängslen {och}). Vänta inte med att deklarera variabler tills deras första användning; det kan förvirra den oväntade programmeraren och hämma kodportabilitet inom räckvidden.

// Föredra () förklara i början av blocket.
public void doSomething () {
  int whatIRepresent; // början på metodblock
  if (villkor) {
    int someFlag; // början av ”if” -block
    ...
  }
}

Det är också viktigt att undvika lokala förklaringar som döljer deklarationer av högre nivåer och att undvika förvirringar som visas nedan

int räkna;
...
public void doSomething () {
  if (villkor) {
    int räkna; // UNDVIKA!
    ...
  }
  ...
}

Mellanrum och rader - Undvik frestelsen att spara 1–2 kodrader på bekostnad av läsbarheten. Här är alla bästa metoder när det gäller avstånd och tomma rader (Ett vitt utrymme gör en skillnad)

  • En (1) blank linje mellan metoder och vårutvecklare rekommenderar två (2) tomma rader efter konstruktörer, statisk block, fält och inre klass
  • Rymdkuddsoperatörer, dvs använd int foo = a + b + 1; över int foo = a + b + 1;
  • Separera alla binära operatörer utom “.” Från operander med ett mellanslag
  • Öppen stag "{" visas i slutet av samma rad som deklarationen eller metoden och stängningsstödet "}" startar en rad av sig själv intryckt
// Föredrag () - Mellanslag efter "medan" och före "("
medan (sant) {
  ...
}
// Undvik (x) - Till skillnad från ovan inget utrymme
medan (sant) {
  ...
}
// Föredrag () - Inget utrymme mellan "doSomething" och "("
public void doSomething () {
  ...
}
// Undvik (x) - Till skillnad från ovan rymden
public void doSomething () {
  ...
}
// Föredrag () - Lägg till ett mellanrum efter ett argument
public void doSomething (int a, int b) {
  ...
}
// Föredrag () - Utrymme mellan operand och operatörer (dvs +, =)
a + = c + d;
a = (a + b) / (c * d);
medan (d ++ = s ++) {
  n ++;
}

Dokumentation och kommentarer

Det är värt att nämna att nästan all kod ändras under hela sin livstid och det kommer att finnas tillfällen då du eller någon försöker ta reda på vad ett komplext block av kod, en metod eller en klass är avsedd att göra om inte tydligt beskrivits. Verkligheten är nästan alltid som följa

Det finns tillfällen att kommentarerna till en komplex kod, metod, klass inte tillför något värde eller tjänar sitt syfte. Detta händer vanligtvis när man kommenterar för det.

Kommentarer ska användas för att ge överblick över koden och ge ytterligare information som inte är lätt tillgänglig i själva koden. Låt oss börja. Det finns två typer av kommentarer

Implementeringskommentarer - är avsedda att kommentera kod eller kommentera om en viss implementering av koden.

Dokumentationskommentarer - är avsedda att beskriva specifikationen av koden ur ett implementeringsfritt perspektiv som ska läsas av utvecklare som kanske inte nödvändigtvis har källkoden till hands.

Kommentars frekvens avspeglar ibland dålig kvalitet på koden. När du känner dig tvungen att lägga till en kommentar kan du överväga att skriva om koden så att den blir tydligare.

Typer av implementeringskommentarer

Det finns fyra (4) typer av implementeringskommentarer som visas nedan

  • Blockera kommentar - se exempel nedan
  • Kommentar med en rad - när kommentaren inte är längre än en rad
  • Efter kommentarer - Mycket kort kommentar flyttade till rätt slut
  • Slut på radens kommentar - börjar en kommentar som fortsätter till den nya raden. Den kan kommentera en komplett rad eller endast en delrad. Det ska inte användas på flera rad i rad för textkommentarer; det kan dock användas i flera rad i rad för att kommentera kodavsnitt.
// Blockera kommentar
/ *
 * Användning: Ger beskrivning av filer, metoder, datastrukturer
 * och algoritmer. Kan användas i början av varje fil och
 * före varje metod. Används för långa kommentarer som inte passar a
 * en kö. 1 Tom linje för att fortsätta efter blockkommentaren.
 * /
// Kommentar med en rad
if (villkor) {
 / * Hantera villkoret. * /
  ...
}
// Efterföljande kommentar
if (a == 2) {
 returnera SANT; /* specialfall */
} annat {
 return isPrime (a); / * fungerar endast för udda a * /
}
// Kommentar i slutet av raden
if (foo> 1) {
  // Gör en dubbel vändning.
  ...
} annat {
  returnera falskt; // Förklara varför här.
}
// if (stapel> 1) {
//
// // Gör en trippling.
// ...
//}
//annan
// returnera falskt;

Dokumentationskommentarer (dvs. Javadoc)

Javadoc är ett verktyg som genererar HTML-dokumentation från din java-kod med kommentarerna som börjar med / ** och slutar med * / - se Wikipedia för mer information om hur Javadoc fungerar eller bara läs med.

Här är ett exempel på Javadoc

/ **
 * Returnerar ett bildobjekt som sedan kan målas på skärmen.
 * URL-argumentet måste ange en absolut {@link URL}. Namnet
 * argument är en specifik som är relativt till url-argumentet.
 * 

 * Denna metod återgår alltid omedelbart, oavsett om  * bilden finns. När denna applet försöker rita bilden på  * på skärmen kommer data att laddas. De grafiska primitiven  * som ritar bilden kommer att måla stegvis på skärmen.  *  * @param url en absolut URL som ger basens plats för bilden  * @param namnge platsen för bilden, relativt url-argumentet  * @ Återvänd bilden till den angivna URL: en  * @see bild  * /  public Image getImage (URL url, String name) {         Prova {             returnera getImage (ny URL (url, namn));         } catch (MalformedURLEexception e) {             return null;         }  }

Och ovanstående skulle resultera i en HTML som följer när javadoc körs mot koden som har ovanstående

Se här för mer

Här är några viktiga taggar som du kan använda för att förbättra kvaliteten på den genererade java-dokumentationen.

@author => @author Raf
@code => {@code A  C}
@deprecated => @deprecated deprecation-meddelande
@exception => @exception IOException kastas när
@link => {@link package.class # medlemsetikett}
@param => @param parameter-namnbeskrivning
@return => Vad metoden returnerar
@see => @see "sträng" ELLER @ se  
@since => Ange versionen när en offentligt tillgänglig metod läggs till

För en fullständig lista och mer detaljerad beskrivning se här

Twitter: s kodningsstandard rekommenderar användning av @author-taggen

Koden kan byta hand flera gånger under sin livstid, och ganska ofta är den ursprungliga författaren till en källfil inte relevant efter flera iterationer. Vi tycker att det är bättre att lita på engagemangshistorik och OWNERS-filer för att fastställa äganderätten till en kod.

Följande är exempel på hur du kan skriva en dokumentationskommentar som är insiktsfull som beskrivs i Twitters kodningsstandard

// Dåligt.
// - Dokumentet berättar ingenting om att metoddeklarationen inte gjorde det.
// - Detta är 'filler doc'. Det skulle passera stilkontroller, men
hjälper inte någon.
/ **
 * Delar en sträng.
 *
 * @param s En sträng.
 * @ return En lista med strängar.
 * /
Lista  split (strängar);
// Bättre.
// - Vi vet vad metoden delar upp.
// - Fortfarande lite odefinierat beteende.
/ **
 * Delar en sträng på blanksteg.
 *
 * @param s Strängen som ska delas. En {@code null} sträng behandlas som en tom sträng.
 * @ return En lista över de delar som är avgränsade med den vita delen av ingången.
 * /
Lista  split (strängar);
// Bra.
// - Täcker ännu ett kantfodral.
/ **
 * Delar en sträng på blanksteg. Upprepade blankstegstecken
 * är kollapsade.
 *
 * @param s Strängen som ska delas. En {@code null} sträng behandlas som en tom sträng.
 * @ return En lista över de delar som är avgränsade med den vita delen av ingången.
 * /
Lista  split (strängar);

Det är viktigt att vara professionell när det gäller att skriva kommentarer

// Undvik (x)
// Jag hatar så mycket xml / soap, varför kan den inte göra det här för mig !?
Prova {
  userId = Integer.parseInt (xml.getField ("id"));
} fånga (NumberFormatException e) {
  ...
}
// Föredrar ()
// TODO (Jim): Tuck field validation borta i ett bibliotek.
Prova {
  userId = Integer.parseInt (xml.getField ("id"));
} fånga (NumberFormatException e) {
  ...
}

Och det är viktigt att komma ihåg att inte dokumentera åsidosatt metod om inte implementeringen har ändrats.

Och här är några fler punkter att komma ihåg

  • Undvik import av jokertecken - som beskrivs i Twitters kodningsstandarder gör det klassens källa mindre tydlig. Jag arbetar i ett team med en blandning av Eclipse- och IntelliJ-användare och jag fick reda på att Eclipse tar bort jokertimporten och IntelliJ introducerar den. Det finns förmodligen ett alternativ att stänga av det, ville bara påpeka standard för de två.
  • Använd alltid @Orride-kommentar när du åsidosätter
  • Uppmuntra användning av @Nullable när ett fält eller metod returnerar noll
  • Använd speciella kommentarer för framtida arbete och glöm inte att lämna en hänvisning till dig själv så att andra vet vem de ska ställa sin Y-fråga istället för att gissa, ta bort den eller kontrollera git-skylden för att hitta vem som har lagt till den. Vissa IDE: er som Eclipse och IntelliJ hjälper också till att lista dessa för enkel åtkomst och en påminnelse.
// FIXME (Raf): Ett handlingsbart meddelande beskriver vad som måste göras
// TODO (Raf): Ett handlingsbart meddelande beskriver vad som måste göras

Slutspelet är att skriva kod som gör livet för framtida författare och underhållare enkelt.

Slutspelet

Andra relevanta läsmaterial

En lista över relevanta artiklar som är relevanta för att skriva kod som är ren, välstrukturerad, lättläst och underhållbar. Om du vill läsa mer, rekommenderar du definitivt följande

och en annan bra lista med tips för att skriva ren kod