Een korte samenvatting van best practices voor codering van Java

gebaseerd op coderingsstandaarden van Oracle, Google, Twitter en Spring Framework

Het doel van dit artikel is om u een snel overzicht te geven van wat u wel en niet moet doen, met andere woorden, voorkeur geven aan en vermijden op basis van coderingsstandaarden van technische reuzen zoals Oracle, Google, Twitter en Spring Framework.

U bent het misschien wel of niet eens met enkele van de hier gepresenteerde best practices, en dat is absoluut prima zolang er een coderingsstandaard is.

Waarom codeerstandaarden überhaupt? Er zijn veel goede redenen als je het googelt en ik zal je de volgende illustratie geven

Document met coderingsstandaarden kan lang en saai zijn. In dit artikel kiest Cherry stukjes en beetjes uit codeerconventies van Google, Oracle, Twitter en Spring. Het heeft als doel u een eenvoudig te volgen en minder saaie reeks werkwijzen te bieden om uw code gemakkelijk te lezen en te onderhouden te maken.

Bijna altijd zul je lid worden van teams die aan bestaande software werken en er is een vrij goede kans dat de meeste auteurs zijn vertrokken of zijn overgestapt op verschillende projecten, waardoor je achterblijft met delen van code die je vragen stellen aan de mensheid.

Laten we de best practices van verschillende codeerstandaarden onder de loep nemen.

Java-bronbestand

Het volgende wordt beschouwd als best practices als het gaat om Java-bronbestanden:

  • De lengte van het bronbestand is minder dan 2000 regels code
  • Het bronbestand is georganiseerd met documentatiecommentaar, pakketdeclaratie, gevolgd door een klassecommentaar, import gegroepeerd (statische laatste), klasse / interfacehandtekening en dergelijke zoals hieronder weergegeven
pakket com.example.model;
/ **
 * Implementatievrij perspectief te lezen door ontwikkelaars
 * die niet noodzakelijkerwijs de broncode bij de hand heeft
 *
 * @auteur x, y, z
 * @Datum
 * @versie
 * @auteursrechten
 *
 * /
import com.example.util.FileUtil;
/ *
 * Optionele klassespecifieke opmerking
 *
 * /
public class SomeClass {
  // Statische variabelen in volgorde van zichtbaarheid
  openbare statische finale Geheel getal PUBLIC_COUNT = 1;
  statisch laatste geheel getal PROTECTED_COUNT = 1;
  privé statisch finaal Geheel getal PRIVATE_COUNT = 1;
  // Instantievariabelen in volgorde van zichtbaarheid
  openbare tekenreeksnaam;
  String PostalCode;
  privé tekenreeksadres;
  // Constructor en overbelast in opeenvolgende volgorde
  public SomeClass () {}
  public SomeClass (tekenreeksnaam) {
    this.name = name;
  }
  // Methoden
  public String doSomethingUseful () {
    terug "Iets nuttigs";
  }
  // getters, setters, is gelijk aan, hashCode en toString aan het einde
}

Naamgeving

Klasse- en interfacenamen zijn CamelCase en het wordt aanbevolen om het hele woord te gebruiken en acroniemen / afkortingen te vermijden. Bijvoorbeeld klasse Raster of klasse ImageSprite

  • Pakket - noemt com.deepspace via com.deepSpace of com.deep_space
  • Bestandsnamen zijn CamelCase en eindigen op .java die overeenkomt met de klassenaam. Er is één openbare klasse per bestand met elke klasse op het hoogste niveau in het bestand
  • Methode - namen moeten werkwoorden zijn in een gemengd geval met elk intern woord in hoofdletters, bijvoorbeeld run (); of runFast ();
  • Constanten - moet een hoofdletter zijn met "_" die elk woord scheidt, bijvoorbeeld int MIN_WIDTH = 44; en int MAX_WIDTH = 99;
  • Variabele - een naam die de lezer van het programma vertelt waar de variabele voor staat, d.w.z. als u een testcijfer opslaat, kies dan cijfer versus var1. Houd de variabelenamen kort vermijd het opnemen van metagegevens.
// Prefer () - namen van variabelen kort en beschrijven wat deze opslaat
int schoolId;
int []filterSchoolIds;
int [] uniqueSchooldIds;
Kaart  gebruikersById;
Tekenreekswaarde;
// Vermijden (x) - Te gedetailleerde naamgeving van variabelen
int schoolIdentificationNumber;
int [] userProvidedSchoolIds;
int [] schoolIdsAfterRemovingDuplicates;
Kaart  idToUserMap;
String valueString;

Onthoud - de naam van de variabele moet kort zijn en de lezer gemakkelijk vertellen welke waarde deze vertegenwoordigt. Gebruik je oordeel.

Voorkeur & Vermijden

Bij het formatteren en inspringen draait alles om het organiseren van uw code zodat deze gemakkelijk te lezen is, en het omvat spatiëring, lijnlengte, wraps en einden, enzovoort

  • Inspringing - Gebruik 2 of 4 spaties en blijf consistent
  • Lijnlengte - Maximaal 70 tot 120 tekens, afhankelijk van de invloed op de leesbaarheid. Het is belangrijk om de noodzaak voor horizontaal scrollen te elimineren en regeleinden te plaatsen na een komma en operator.

Methoden - Hier is een lijst met best practices

// Liever () Regeleindes zijn willekeurig en worden afgebroken na een komma.
String downloadAnInternet (internet internet, buizen buizen,
    Blogosphere blogs, bedrag  bandbreedte) {
  tubes.download (internet);
}
// Vermijd (x) Moeilijk te onderscheiden methode is afhankelijk van de methode
String downloadAnInternet (internet internet, buizen buizen,
    Blogosphere blogs, bedrag  bandbreedte) {
    tubes.download (internet);
}
// Prefer () Voeg 8 (dubbel van 2 of 4) spaties toe voor diep inspringen
private statische gesynchroniseerde horkingLongMethodName (int anArg,
        Object anotherArg, String yetAnotherArg,
        Object andStillAnother) {
  ...
}
// Prefer () Eenvoudig scannen en extra kolomruimte.
openbare tekenreeksdownloadAnInternet (
    Internet internet,
    Buizen buizen,
    Blogosphere blogs,
    Bedrag  bandbreedte) {
  tubes.download (internet);
  ...
}
Een eenheidstest zou dat hebben opgevangen

If-checks - IMO die goed opgemaakte code schrijft, maakt het gemakkelijk om typefouten en fouten te herkennen aan de auteur en de code reviewers, zie hieronder:

// Vermijden (x) Niet weglaten {}
if (voorwaarde)
  uitspraak;
// Vermijden (x)
indien (x <0) negatief (x);
// Vermijden (x)
if (a == b && c == d) {
...
}
// Voorkeur ()
if ((a == b) && (c == d)) {
...
}
// Voorkeur ()
if (voorwaarde) {
  statements;
} anders if (voorwaarde) {
  statements;
} anders if (voorwaarde) {
  statements;
}
// Vermijden (x)
if ((voorwaarde1 && voorwaarde2)
    || (staat3 && staat4)
    ||! (condition5 && condition6)) {// SLECHTE WRAPS
    doe er iets aan(); // MAAK DEZE LIJN GEMAKKELIJK TE MISSEN
}
// Voorkeur ()
if ((voorwaarde1 && voorwaarde2)
        || (staat3 && staat4)
        ||! (condition5 && condition6)) {
    doe er iets aan();
}

Ternary-operator - En hieronder staan ​​aanbevolen werkwijzen

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

Schakelaar - Als het aankomt op overschakelen, is dit de beste praktijk

  • Heb altijd een standaardgeval, zelfs zonder code
  • Gebruik / * valt door * / om aan te geven dat de besturing naar het volgende geval valt
schakelaar (staat) {
  zaak ABC:
    statements;
  / * valt door * /
  zaak DEF:
    statements;
    breken;
  standaard:
    statements;
     breken;
}

Uitzonderingsberichten - Hier zijn voorbeelden van goede en slecht ingesprongen berichten.

// Vermijden (x) - Niet gemakkelijk te lezen
gooi nieuwe IllegalStateException ("Kan verzoek niet verwerken" + request.getId ()
    + "for user" + user.getId () + "query: '" + query.getText ()
    + "'");
// Liever () - Redelijk gemakkelijker te lezen
gooi nieuwe IllegalStateException ("Kan niet verwerken"
    + "request" + request.getId ()
    + "voor gebruiker" + user.getId ()
    + "query: '" + query.getText () + "'");

Iterators en streams - streams worden steeds gebruikelijker en soms kan het erg complex zijn, daarom is het belangrijk om in te springen om gemakkelijk te lezen te zijn.

// Vermijden (x) - Niet gemakkelijk te lezen
Iterable  modules = ImmutableList.  builder (). Add (nieuwe LifecycleModule ())
    .add (nieuwe AppLauncherModule ()). addAll (application.getModules ()). build ();
// Liever () - Redelijk gemakkelijker te lezen
Iterable  modules = ImmutableList.  builder ()
    .add (nieuwe LifecycleModule ())
    .add (nieuwe AppLauncherModule ())
    .addAll (application.getModules ())
    .bouwen();
Volg gewoon een coderingsstandaard - eigenlijk

Verklaringen en toewijzingen— Eén verklaring per regel wordt aanbevolen, omdat dit opmerkingen aanmoedigt zoals hieronder wordt weergegeven.

// Voorkeur ()
int niveau; // inspringingsniveau
int sizeMeter; // grootte van de tafel
// Vermijd (x) voor bovenstaande
int level, sizeMeter;
// Prefer () - Neem de eenheid op in de naam of het type van de variabele
lange pollIntervalMs;
int fileSizeGb;
Bedrag  fileSize;
// Vermijd (x) mengingstypen
int foo, fooarray [];
// Vermijden (x) - Niet scheiden met komma
Format.print (System.out, "error"), exit (1);
// Vermijd (x) meervoudige toewijzing
fooBar.fChar = barFoo.lchar = 'c';
// Vermijd (x) ingesloten opdrachten in een poging de prestaties te verbeteren // of een lijn op te slaan. Ik ben hier schuldig aan :(
d = (a = b + c) + r;
// Liever () boven
a = b + c;
d = a + r;
// Voorkeur ()
String [] args
// Vermijden (x)
String args []
// Liever () Gebruik lang "L" in plaats van "l" om verwarring met 1 te voorkomen
lange time-out = 3000000000L;
// Vermijd (x) - Moeilijk om de laatste letter te vertellen is l en niet 1
lange time-out = 3000000000l;

Plaats declaraties alleen aan het begin van blokken (een blok is code omgeven door accolades {en}). Wacht niet om variabelen te declareren tot hun eerste gebruik; het kan de onoplettende programmeur verwarren en codeportabiliteit belemmeren binnen het bereik.

// Prefer () verklaren aan het begin van het blok.
public void doSomething () {
  int whatIRepresent; // begin van methodeblok
  if (voorwaarde) {
    int someFlag; // begin van het "if" -blok
    ...
  }
}

Het is ook belangrijk om lokale verklaringen te vermijden die verklaringen van de hogere niveaus verbergen en om verwarring te vermijden zoals hieronder getoond

int tellen;
...
public void doSomething () {
  if (voorwaarde) {
    int tellen; // VERMIJDEN!
    ...
  }
  ...
}

Spatiëring en regeleinden - Vermijd de verleiding om 1-2 coderegels op te slaan ten koste van de leesbaarheid. Hier zijn alle praktische tips als het gaat om spatiëring en lege lijnen (een witte spatie maakt een verschil)

  • Eén (1) lege regel tussen methoden en Spring-ontwikkelaars beveelt twee (2) lege regels aan na constructors, statisch blok, velden en binnenklasse
  • Spatiepadoperatoren d.w.z. Gebruik int foo = a + b + 1; over int foo = a + b + 1;
  • Scheid alle binaire operatoren behalve "." Van operanden met een spatie
  • Open accolade "{" verschijnt aan het einde van dezelfde regel als de aangifte of methode en sluit accolade "}" begint een regel op zichzelf ingesprongen
// Prefer () - Spatie na "while" en before "("
terwijl (waar) {
  ...
}
// Vermijd (x) - In tegenstelling tot hierboven geen spatie
terwijl (waar) {
  ...
}
// Prefer () - Geen spatie tussen "doSomething" en "("
public void doSomething () {
  ...
}
// Vermijd (x) - in tegenstelling tot bovenstaande ruimte
public void doSomething () {
  ...
}
// Prefer () - Voeg een spatie toe na een argument
public void doSomething (int a, int b) {
  ...
}
// Prefer () - Ruimte tussen operand en operatoren (d.w.z. +, =)
a + = c + d;
a = (a + b) / (c * d);
terwijl (d ++ = s ++) {
  n ++;
}

Documentatie en opmerkingen

Het is vermeldenswaard dat bijna alle code tijdens zijn levensduur verandert en dat er momenten zijn waarop jij of iemand probeert uit te zoeken wat een complex codeblok, een methode of een klasse is bedoeld, tenzij duidelijk beschreven. De realiteit is bijna altijd als volgt

Er zijn tijden dat de opmerking over een complex stuk code, methode of klasse geen waarde toevoegt of zijn doel dient. Dit gebeurt meestal wanneer er commentaar wordt gegeven.

Opmerkingen moeten worden gebruikt om overzichten van code te geven en aanvullende informatie te geven die niet direct beschikbaar is in de code zelf. Laten we beginnen. Er zijn twee soorten opmerkingen

Implementatiereacties - zijn bedoeld om commentaar op een code of commentaar op een bepaalde implementatie van de code te geven.

Documentatiereacties - zijn bedoeld om de specificatie van de code te beschrijven vanuit een implementatie-vrij perspectief dat moet worden gelezen door ontwikkelaars die niet noodzakelijkerwijs de broncode bij de hand hebben.

De frequentie van opmerkingen weerspiegelt soms de slechte kwaliteit van de code. Als u zich genoodzaakt voelt een opmerking toe te voegen, kunt u overwegen de code te herschrijven om deze duidelijker te maken.

Soorten implementatiereacties

Er zijn vier (4) soorten implementatiereacties zoals hieronder weergegeven

  • Blokkeer commentaar - zie voorbeeld hieronder
  • Opmerking over één regel - wanneer de opmerking niet langer is dan een regel
  • Trailing comments - Zeer korte reactie verplaatst naar het juiste einde
  • Reactie einde regel - begint een opmerking die doorgaat naar de nieuwe regel. Het kan een volledige regel of slechts een gedeeltelijke regel becommentariëren. Het mag niet worden gebruikt op opeenvolgende meerdere regels voor tekstopmerkingen; het kan echter worden gebruikt in opeenvolgende meerdere regels voor het becommentariëren van secties code.
// Reactie blokkeren
/ *
 * Gebruik: biedt een beschrijving van bestanden, methoden en gegevensstructuren
 * en algoritmen. Kan aan het begin van elk bestand worden gebruikt en
 * voor elke methode. Gebruikt voor lange opmerkingen die niet passen a
 * enkele lijn. 1 Lege regel om verder te gaan na de blokcommentaar.
 * /
// Enkele regel commentaar
if (voorwaarde) {
 / * Omgaan met de voorwaarde. * /
  ...
}
// Laatste reactie
if (a == 2) {
 retourneer WAAR; /* speciaal geval */
} anders {
 retour isPrime (a); / * werkt alleen voor oneven * /
}
// Commentaar aan het einde van de regel
if (foo> 1) {
  // Doe een dubbele flip.
  ...
} anders {
  return false; // Leg uit waarom hier.
}
// if (balk> 1) {
//
// // Doe drie keer om.
// ...
//}
//anders
// return false;

Documentatiereacties (d.w.z. Javadoc)

Javadoc is een tool die HTML-documentatie van uw Java-code genereert met behulp van de opmerkingen die beginnen met / ** en eindigen met * / - zie Wikipedia voor meer informatie over hoe Javadoc werkt of lees gewoon mee.

Hier is een voorbeeld van Javadoc

/ **
 * Retourneert een afbeeldingobject dat vervolgens op het scherm kan worden geschilderd.
 * Het url-argument moet een absolute {@link URL} specificeren. De naam
 * argument is een specificatie die relatief is aan het url-argument.
 * 

 * Deze methode keert altijd onmiddellijk terug, ongeacht of  * afbeelding bestaat. Wanneer deze applet de afbeelding probeert te tekenen  * op het scherm worden de gegevens geladen. De grafische primitieven  * die de afbeelding tekenen, worden stapsgewijs op het scherm weergegeven.  *  * @param url een absolute URL met de basislocatie van de afbeelding  * @param geeft de locatie van de afbeelding een relatieve waarde ten opzichte van het argument url  * @keer de afbeelding terug naar de opgegeven URL  * @zie afbeelding  * /  openbare afbeelding getImage (URL-URL, tekenreeksnaam) {         proberen {             retourneer getImage (nieuwe URL (url, naam));         } vangst (MalformedURLException e) {             terugkeer null;         }  }

En het bovenstaande zou resulteren in een HTML als volgt wanneer javadoc wordt uitgevoerd tegen de code die de bovenstaande heeft

Kijk hier voor meer informatie

Hier zijn enkele belangrijke tags die u kunt gebruiken om de kwaliteit van de gegenereerde Java-documentatie te verbeteren.

@author => @author Raf
@code => {@code A  C}
@deprecated => @deprecated deprecation-bericht
@exception => @exception IOException gegooid wanneer
@link => {@link package.class # lidlabel}
@param => @param parameternaambeschrijving
@return => Wat de methode retourneert
@see => @see "string" OF @see  
@since => Om de versie aan te geven wanneer een openbaar toegankelijke methode is toegevoegd

Voor een volledige lijst en een meer gedetailleerde beschrijving zie hier

De codeerstandaard van Twitter raadt het gebruik van de @author-tag af

Code kan in zijn leven talloze keren van eigenaar veranderen en de originele auteur van een bronbestand is vaak niet relevant na verschillende iteraties. We vinden het beter om commit-geschiedenis en OWNERS-bestanden te vertrouwen om het eigendom van een geheel van code te bepalen.

Hieronder volgen voorbeelden van hoe u een documentatiecommentaar kunt schrijven dat inzichtelijk is, zoals beschreven in de coderingsstandaard van Twitter

// Slecht.
// - Het document zegt niets dat de methodedeclaratie niet deed.
// - Dit is het 'opvullerdocument'. Het zou stijlcontroles doorstaan, maar
helpt niemand.
/ **
 * Splitst een string.
 *
 * @param s Een tekenreeks.
 * @return Een lijst met tekenreeksen.
 * /
Lijst  split (String s);
// Beter.
// - We weten waarop de methode zich splitst.
// - Nog steeds ongedefinieerd gedrag.
/ **
 * Splitst een string op witruimte.
 *
 * @param s De te splitsen string. Een {@code null} -reeks wordt behandeld als een lege reeks.
 * @return Een lijst met de witruimte-gescheiden delen van de invoer.
 * /
Lijst  split (String s);
// Super goed.
// - Omvat nog een randgeval.
/ **
 * Splitst een string op witruimte. Herhaalde witruimte tekens
 * zijn ingestort.
 *
 * @param s De te splitsen string. Een {@code null} -reeks wordt behandeld als een lege reeks.
 * @return Een lijst met de witruimte-gescheiden delen van de invoer.
 * /
Lijst  split (String s);

Het is belangrijk om professioneel te zijn als het gaat om het schrijven van opmerkingen

// Vermijden (x)
// Ik haat zoveel xml / soap, waarom kan het dit niet voor mij doen !?
proberen {
  userId = Integer.parseInt (xml.getField ("id"));
} catch (NumberFormatException e) {
  ...
}
// Voorkeur ()
// TODO (Jim): stop veldvalidatie weg in een bibliotheek.
proberen {
  userId = Integer.parseInt (xml.getField ("id"));
} catch (NumberFormatException e) {
  ...
}

En het is belangrijk om te onthouden dat u de overschreven methode niet documenteert, tenzij de implementatie is gewijzigd.

En hier zijn nog een paar punten om in gedachten te houden

  • Vermijd wildcard-invoer - zoals beschreven in de coderingsstandaarden van Twitter maakt het de bron van klasse minder duidelijk. Ik werk in een team met een mix van Eclipse- en IntelliJ-gebruikers en ontdekte dat Eclipse wildcard-invoer verwijdert en IntelliJ het introduceert. Er is waarschijnlijk een optie om het uit te schakelen, ik wilde alleen de standaard voor de twee aangeven.
  • Gebruik altijd @Override annotatie wanneer u overschrijft
  • Moedig het gebruik van @Nullable aan wanneer een veld of methode null retourneert
  • Gebruik speciale opmerkingen voor toekomstig werk en vergeet niet om een ​​verwijzing naar jezelf achter te laten, zodat anderen weten wie ze hun Y-vraag moeten stellen in plaats van te raden, te verwijderen of de schuld te controleren om erachter te komen wie het heeft toegevoegd. Sommige IDE's zoals Eclipse en IntelliJ helpen ook bij het vermelden van deze voor gemakkelijke toegang en een herinnering.
// FIXME (Raf): een uitvoerbaar bericht beschrijft wat er moet worden gedaan
// TODO (Raf): een uitvoerbaar bericht beschrijft wat er moet worden gedaan

Het eindspel is om code te schrijven die het leven van toekomstige auteurs en beheerders gemakkelijk maakt.

Het eindspel

Andere relevante leesmaterialen

Een lijst met relevante artikelen die relevant zijn voor het schrijven van code die schoon, goed gestructureerd, gemakkelijk te lezen en te onderhouden is. Als je meer wilt lezen, raad dan zeker het volgende aan

en nog een goede lijst met tips voor het schrijven van schone code