Krótkie podsumowanie najlepszych praktyk kodowania Java

w oparciu o standardy kodowania Oracle, Google, Twitter i Spring Framework

Celem tego artykułu jest szybkie podsumowanie czynności, których nie należy, innymi słowy, preferuj i unikaj w oparciu o standardy kodowania od gigantów technologicznych, takich jak Oracle, Google, Twitter i Spring Framework.

Możesz zgodzić się z niektórymi z najlepszych praktyk przedstawionych tutaj lub nie, i jest to absolutnie w porządku, o ile istnieje jakiś standard kodowania.

Po co przede wszystkim kodować standardy? Istnieje wiele dobrych powodów, jeśli Google to zrobisz, a ja zostawię ci następującą ilustrację

Dokument standardów kodowania może być długi i nudny. W tym artykule wiśnia zbiera drobiazgi z konwencji kodowania Google, Oracle, Twitter i Spring, a jej celem jest zapewnienie łatwego do naśladowania i mniej nudnego zestawu praktyk ułatwiających czytanie i utrzymywanie kodu.

Prawie zawsze dołączasz do zespołów pracujących nad istniejącym oprogramowaniem i istnieje spora szansa, że ​​większość autorów opuściła inne projekty lub przeszła na inne projekty, pozostawiając ci części kodu, które powodują, że kwestionujesz ludzkość.

Zajrzyjmy do najlepszych praktyk z różnych standardów kodowania.

Plik źródłowy Java

Poniżej przedstawiono najlepsze praktyki dotyczące plików źródłowych Java:

  • Długość pliku źródłowego jest mniejsza niż 2000 linii kodu
  • Plik źródłowy jest zorganizowany z komentarzem do dokumentacji, deklaracją pakietu, a następnie komentarzem do klasy, importem pogrupowanym (statycznie ostatni), podpisem klasy / interfejsu i tak dalej, jak pokazano poniżej
pakiet com.example.model;
/ **
 * Perspektywa bez implementacji do odczytania przez programistów
 * który niekoniecznie musi mieć pod ręką kod źródłowy
 *
 * @ autor x, y, z
 * @data
 * @wersja
 * @Prawo autorskie
 *
 * /
import com.example.util.FileUtil;
/ *
 * Opcjonalny komentarz specyficzny dla klasy
 *
 * /
klasa publiczna SomeClass {
  // Zmienne statyczne w kolejności widoczności
  publiczna statyczna końcowa liczba całkowita PUBLIC_COUNT = 1;
  statyczna końcowa liczba całkowita PROTECTED_COUNT = 1;
  prywatna statyczna końcowa liczba całkowita PRIVATE_COUNT = 1;
  // Zmienne instancji w kolejności widoczności
  publiczna nazwa ciągu;
  String postalCode;
  prywatny ciąg znaków;
  // Konstruktor i przeciążony w kolejności sekwencyjnej
  public SomeClass () {}
  public SomeClass (nazwa ciągu) {
    this.name = nazwa;
  }
  // Metody
  public String doSomethingUseful () {
    return „Coś przydatnego”;
  }
  // getters, setters, equals, hashCode i toString na końcu
}

Nazewnictwo

Nazwy klas i interfejsów to CamelCase i zaleca się stosowanie całego słowa i unikanie akronimów / skrótów. Na przykład klasa Raster lub klasa ImageSprite

  • Pakiet - nazwy com.deepspace nad com.deepSpace lub com.deep_space
  • Nazwy plików to CamelCase i kończą się rozszerzeniem .java pasującym do nazwy klasy. Na plik przypada jedna klasa publiczna z każdą klasą najwyższego poziomu w pliku
  • Metoda - nazwy powinny być czasownikami wielkimi i małymi literami, a każde wewnętrzne słowo pisane wielkimi literami, na przykład run (); lub runFast ();
  • Stałe - powinny być pisane wielkimi literami z „_” oddzielającymi poszczególne słowa, na przykład int MIN_WIDTH = 44; i int MAX_WIDTH = 99;
  • Zmienna - nazwa, która mówi czytelnikowi programu, co reprezentuje zmienna, tj. Jeśli przechowujesz ocenę testową, wybierz ocenę vs var1. Zachowaj krótkie nazwy zmiennych, w tym metadane.
// Preferuj () - krótkie nazwy zmiennych i opisuj, co je przechowuje
int schoolId;
int [] filterSchoolIds;
int [] uniqueSchooldIds;
Mapa  usersById;
Wartość ciągu;
// Unikaj (x) - Zbyt szczegółowe nazewnictwo zmiennych
int schoolIdentificationNumber;
int [] userProvidedSchoolIds;
int [] schoolIdsAfterRemovingDuplicates;
Mapa  idToUserMap;
String valueString;

Pamiętaj - nazwa zmiennej powinna być krótka i łatwo powiedzieć czytelnikowi, jaką wartość reprezentuje. Wykorzystaj swój osąd.

Wolę i unikaj

Formatowanie i wcięcia mają na celu uporządkowanie kodu w celu ułatwienia jego odczytu. Obejmuje on odstępy, długość linii, zawijanie i łamanie itd.

  • Wcięcie - użyj 2 lub 4 spacji i zachowaj spójność
  • Długość linii - do 70 do 120 znaków w zależności od wpływu na czytelność. Ważne jest, aby wyeliminować potrzebę przewijania w poziomie i wstawiania podziałów po przecinku i operatorze.

Metody - Oto lista najlepszych praktyk

// Preferuj () Podziały linii są dowolne i łamane po przecinku.
Pobieranie ciągów Internet (Internet Internet, Tuby,
    Blogi blogosfery, ilość pasma ) {
  pobieranie rur (internet);
}
// Unikaj (x) Trudna do porównania metoda argumentuje ciało metody
Pobieranie ciągów Internet (Internet Internet, Tuby,
    Blogi blogosfery, ilość pasma ) {
    pobieranie rur (internet);
}
// Preferuj () Dodaj 8 (podwójne 2 lub 4) spacje dla głębokiego wcięcia
private static synchronized horkingLongMethodName (int anArg,
        Object anotherArg, String yetAnotherArg,
        Object andStillAnother) {
  ...
}
// Preferuj () Łatwe skanowanie i dodatkowe miejsce na kolumny.
public String downloadAnInternet (
    Internet internetowy,
    Rury,
    Blogi blogosfery,
    Kwota ) {
  pobieranie rur (internet);
  ...
}
Test jednostkowy by to wychwycił

Jeśli-sprawdza - IMO pisze dobrze sformatowany kod ułatwia wykrywanie literówek i błędów dla autora i recenzentów kodu, patrz poniżej:

// Unikaj (x) Nie pomijaj {}
jeśli (warunek)
  komunikat;
// Unikaj (x)
jeśli (x <0) ujemne (x);
// Unikaj (x)
jeśli (a == b && c == d) {
...
}
// Preferuj ()
jeśli ((a == b) i& (c == d)) {
...
}
// Preferuj ()
if (warunek) {
  sprawozdania;
} else if (condition) {
  sprawozdania;
} else if (condition) {
  sprawozdania;
}
// Unikaj (x)
if ((warunek 1 i & warunek 2)
    || (warunek 3 i & warunek 4)
    ||! (warunek5 i&warunek6)) {// ZŁE ZWIJKI
    doSomethingAboutIt (); // ZRÓB TEN LINIĘ ŁATWY DO BRAKU
}
// Preferuj ()
if ((warunek 1 i & warunek 2)
        || (warunek 3 i & warunek 4)
        ||! (condition5 && condition6)) {
    doSomethingAboutIt ();
}

Operator trójskładnikowy - i poniżej są zalecane praktyki

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

Przełącz - jeśli chodzi o przełączanie, najlepszą praktyką jest

  • Zawsze mają domyślną wielkość liter, nawet bez kodu
  • Użyj / * spada przez * /, aby wskazać, że kontrola spada do następnego przypadku
przełącznik (warunek) {
  przypadek ABC:
    sprawozdania;
  / * wpada * /
  sprawa DEF:
    sprawozdania;
    przerwa;
  domyślna:
    sprawozdania;
     przerwa;
}

Komunikaty wyjątków - Zgłaszając wyjątek, podajemy przykłady dobrych i słabo wciętych wiadomości.

// Unikaj (x) - Niełatwy do odczytania
zgłosić nowy wyjątek IllegalStateException („Przetwarzanie żądania nie powiodło się” + request.getId ()
    + „dla użytkownika” + user.getId () + „query: '” + query.getText ()
    + „” ”);
// Preferuj () - Dość łatwy do odczytania
zgłosić nowy wyjątek IllegalStateException („Przetwarzanie nie powiodło się”
    + „request” + request.getId ()
    + „dla użytkownika” + user.getId ()
    + „query: '” + query.getText () + „” ”);

Iteratory i strumienie - strumienie stają się coraz bardziej popularne, a czasami mogą być bardzo złożone, dlatego ważne jest, aby wcięcia były łatwe do odczytania.

// Unikaj (x) - Niełatwy do odczytania
Iterable  moduły = ImmutableList.  builder (). Add (new LifecycleModule ())
    .add (new AppLauncherModule ()). addAll (application.getModules ()). build ();
// Preferuj () - Dość łatwy do odczytania
Iterable  moduły = ImmutableList.  builder ()
    .add (nowy LifecycleModule ())
    .add (nowy AppLauncherModule ())
    .addAll (application.getModules ())
    .budować();
Postępuj zgodnie ze standardem kodowania - tak naprawdę

Deklaracje i zadania - Zaleca się jedną deklarację w wierszu, ponieważ zachęca do komentarzy, jak pokazano poniżej.

// Preferuj ()
poziom wewnętrzny; // poziom wcięcia
int sizeMeter; // rozmiar stołu
// Unikaj (x) na korzyść powyższego
poziom wewnętrzny, sizeMeter;
// Preferuj () - Uwzględnij jednostkę w nazwie lub typie zmiennej
long pollIntervalMs;
int fileSizeGb;
Kwota  rozmiar pliku;
// Unikaj (x) mieszania typów
int foo, fooarray [];
// Unikaj (x) - Nie oddzielaj przecinkiem
Format.print (System.out, „error”), exit (1);
// Unikaj (x) wielokrotnego przypisania
fooBar.fChar = barFoo.lchar = 'c';
// Unikaj (x) osadzonych przypisań w celu zwiększenia wydajności // lub zapisania linii. Jestem tego winny :(
d = (a = b + c) + r;
// Wolę () niż wyżej
a = b + c;
d = a + r;
// Preferuj ()
Argumenty String []
// Unikaj (x)
Argumenty ciągu []
// Wolę () Długie użycie „L” zamiast „l”, aby uniknąć pomyłki z 1
długi limit czasu = 3000000000L;
// Unikaj (x) - Trudno powiedzieć, że ostatnia litera to l, a nie 1
długi limit czasu = 3000000000l;

Umieść deklaracje tylko na początku bloków (blok jest kodem otoczonym nawiasami klamrowymi {i}). Nie czekaj, aby zadeklarować zmienne do ich pierwszego użycia; może mylić nieostrożny programator i utrudniać przenoszenie kodu w zakresie.

// Preferuj () deklaruj na początku bloku.
public void doSomething () {
  int whatIRepresent; // początek bloku metody
  if (warunek) {
    int someFlag; // początek bloku „if”
    …
  }
}

Ważne jest również, aby unikać lokalnych deklaracji, które ukrywają deklaracje wyższych poziomów i aby uniknąć nieporozumień, jak pokazano poniżej

int liczba;
...
public void doSomething () {
  if (warunek) {
    int liczba; // UNIKAJ!
    ...
  }
  ...
}

Odstępy i podziały wierszy - Unikaj pokusy zapisania 1–2 wierszy kodu kosztem czytelności. Oto wszystkie najlepsze praktyki dotyczące odstępów i pustych linii (biała spacja robi różnicę)

  • Jedna (1) pusta linia między metodami a programistami Spring zaleca dwie (2) puste linie po konstruktorach, bloku statycznym, polach i klasie wewnętrznej
  • Operatory spacji, tj. Użyj int foo = a + b + 1; ponad int foo = a + b + 1;
  • Oddziel wszystkie operatory binarne oprócz „.” Od operandów, używając spacji
  • Nawias klamrowy „{” pojawia się na końcu tego samego wiersza, co instrukcja lub metoda deklaracji, a nawias zamykający „}” sam zaczyna wcięcie
// Preferuj () - spacja po „while” i przed „(”
podczas gdy (prawda) {
  ...
}
// Unikaj (x) - W przeciwieństwie do powyższego brak spacji
podczas gdy (prawda) {
  ...
}
// Preferuj () - Brak spacji między „doSomething” a „(”
public void doSomething () {
  ...
}
// Unikaj (x) - W przeciwieństwie do miejsca nad przestrzenią
public void doSomething () {
  ...
}
// Preferuj () - Dodaj spację po argumencie
public void doSomething (int a, int b) {
  ...
}
// Preferuj () - odstęp między operandem a operatorami (tj. +, =)
a + = c + d;
a = (a + b) / (c * d);
while (d ++ = s ++) {
  n ++;
}

Dokumentacja i komentarze

Warto wspomnieć, że prawie cały kod zmienia się przez cały okres jego istnienia i będą chwile, gdy ty lub ktoś będzie próbował dowiedzieć się, do czego służy złożony blok kodu, metoda lub klasa, chyba że zostanie to wyraźnie opisane. Rzeczywistość jest prawie zawsze następująca

Czasami komentarz do złożonego fragmentu kodu, metody, klasy nie dodaje żadnej wartości ani nie spełnia swojego celu. Zdarza się to zwykle podczas komentowania ze względu na to.

Komentarze powinny służyć do przeglądania kodu i dostarczania dodatkowych informacji, które nie są łatwo dostępne w samym kodzie. Zacznijmy. Istnieją dwa rodzaje komentarzy

Komentarze do implementacji - mają na celu komentowanie kodu lub komentowanie konkretnej implementacji kodu.

Komentarze do dokumentacji - mają na celu opisanie specyfikacji kodu z perspektywy wolnej od implementacji, do przeczytania przez programistów, którzy niekoniecznie mają pod ręką kod źródłowy.

Częstotliwość komentarzy czasami odzwierciedla słabą jakość kodu. Jeśli czujesz się zmuszony do dodania komentarza, rozważ przepisanie kodu, aby był bardziej przejrzysty.

Rodzaje komentarzy do wdrożenia

Istnieją cztery (4) typy komentarzy do implementacji, jak pokazano poniżej

  • Zablokuj komentarz - patrz przykład poniżej
  • Komentarz jednowierszowy - gdy komentarz nie jest dłuższy niż wiersz
  • Końcowe komentarze - bardzo krótki komentarz został przeniesiony na prawy koniec
  • Komentarz na końcu wiersza - rozpoczyna komentarz, który przechodzi do nowej linii. Może komentować całą linię lub tylko linię częściową. Nie należy go używać w kolejnych wierszach dla komentarzy tekstowych; Można go jednak używać w kilku kolejnych wierszach do komentowania sekcji kodu.
// Zablokuj komentarz
/ *
 * Zastosowanie: Zawiera opis plików, metod, struktur danych
 * i algorytmy. Może być używany na początku każdego pliku i
 * przed każdą metodą. Używany do długich komentarzy, które nie pasują do
 * pojedyncza linia. 1 Pusty wiersz, aby kontynuować po komentarzu do bloku.
 * /
// Komentarz jednowierszowy
if (warunek) {
 / * Obsługuj warunek. * /
  ...
}
// Końcowy komentarz
jeśli (a == 2) {
 zwraca PRAWDA; /* szczególny przypadek */
} else {
 return isPrime (a); / * działa tylko dla nieparzystych a * /
}
// Komentarz na końcu wiersza
if (foo> 1) {
  // Wykonaj podwójne odwrócenie.
  ...
} else {
  zwracać fałsz; // Wyjaśnij, dlaczego tutaj.
}
// if (bar> 1) {
//
// Wykonaj potrójne przewrócenie.
// ...
//}
//jeszcze
// zwróć false;

Komentarze do dokumentacji (tj. Javadoc)

Javadoc to narzędzie, które generuje dokumentację HTML z kodu Java za pomocą komentarzy rozpoczynających się od / ** i kończących się na * / - patrz Wikipedia, aby uzyskać więcej informacji na temat działania Javadoc lub po prostu czytać dalej.

Oto przykład Javadoc

/ **
 * Zwraca obiekt obrazu, który można następnie pomalować na ekranie.
 * Argument adresu URL musi określać bezwzględny {@link URL}. Imię
 * argument jest specyfikatorem odnoszącym się do argumentu url.
 * 

 * Ta metoda zawsze zwraca natychmiast, niezależnie od tego, czy  * obraz istnieje. Gdy ten aplet próbuje narysować obraz  * ekran, dane zostaną załadowane. Prymitywy graficzne  *, które narysują obraz, będą stopniowo malować na ekranie.  *  * @param url bezwzględny adres URL podający podstawową lokalizację obrazu  * @param nazwa lokalizacji obrazu w stosunku do argumentu url  * @ zwróć obraz pod podanym adresem URL  * @ patrz zdjęcie  * /  publiczny obraz getImage (adres URL, nazwa ciągu) {         próbować {             return getImage (nowy adres URL (adres URL, nazwa));         } catch (MalformedURLException e) {             zwraca null;         }  }

Powyższe spowoduje powstanie kodu HTML, jak poniżej, gdy javadoc jest uruchamiany z kodem, który ma powyższe

Zobacz tutaj po więcej

Oto kilka kluczowych tagów, których można użyć do poprawy jakości generowanej dokumentacji Java.

@author => @autor Raf
@code => {@code A  C}
@deprecated => @deprecated deprecation-message
@exception => @exception IOException zgłaszane, kiedy
@link => {@link package.class # etykieta członka}
@param => @param opis parametru-nazwy
@return => Co zwraca metoda
@ patrz => @ patrz „ciąg” LUB @ patrz  
@since => Aby wskazać wersję po dodaniu publicznie dostępnej metody

Aby uzyskać pełną listę i bardziej szczegółowy opis, zobacz tutaj

Standard kodowania Twittera odradza stosowanie tagu @author

Kod może zmieniać ręce wiele razy w ciągu swojego życia i dość często oryginalny autor pliku źródłowego nie ma znaczenia po kilku iteracjach. Uważamy, że lepiej jest zaufać historii zatwierdzeń i plikom WŁAŚCICIELI, aby określić własność części kodu.

Poniżej znajdują się przykłady tego, jak napisać komentarz do dokumentacji, który jest wnikliwy, jak opisano w standardzie kodowania Twittera

// Zły.
// - Dokument nic nie mówi, że deklaracja metody nie.
// - To jest „dokument wypełniający”. Przeszedłby testy stylu, ale
nikomu nie pomaga.
/ **
 * Dzieli ciąg.
 *
 * @param s Ciąg.
 * @return Lista ciągów znaków.
 * /
List  split (String s);
// Lepszy.
// - Wiemy, co dzieli metoda.
// - Wciąż pewne nieokreślone zachowanie.
/ **
 * Dzieli ciąg znaków na białe znaki.
 *
 * @param s Ciąg do podzielenia. Ciąg {@code null} jest traktowany jako pusty ciąg.
 * @return Lista rozdzielonych spacjami części danych wejściowych.
 * /
List  split (String s);
// Wspaniały.
// - Obejmuje kolejną obudowę krawędzi.
/ **
 * Dzieli ciąg znaków na białe znaki. Powtarzające się białe znaki
 * są zwinięte.
 *
 * @param s Ciąg do podzielenia. Ciąg {@code null} jest traktowany jako pusty ciąg.
 * @return Lista rozdzielonych spacjami części danych wejściowych.
 * /
List  split (String s);

Ważne jest, aby być profesjonalnym, jeśli chodzi o pisanie komentarzy

// Unikaj (x)
// Nienawidzę xml / mydła tak bardzo, dlaczego nie może tego dla mnie zrobić !?
próbować {
  userId = Integer.parseInt (xml.getField („id”));
} catch (NumberFormatException e) {
  ...
}
// Preferuj ()
// TODO (Jim): Sprawdzanie poprawności pola ukrytego w bibliotece.
próbować {
  userId = Integer.parseInt (xml.getField („id”));
} catch (NumberFormatException e) {
  ...
}

Ważne jest, aby pamiętać, aby nie dokumentować zastąpionej metody, chyba że implementacja uległa zmianie.

A oto jeszcze kilka punktów, o których warto pamiętać

  • Unikaj importowania symboli wieloznacznych - jak opisano w standardach kodowania Twittera, źródło klasy jest mniej jasne. Pracuję w zespole z mieszanką użytkowników Eclipse i IntelliJ i dowiedziałem się, że Eclipse usuwa importowanie symboli wieloznacznych i IntelliJ to wprowadza. Prawdopodobnie jest opcja, aby ją wyłączyć, chciałem tylko wskazać domyślną dla tych dwóch.
  • Zawsze używaj adnotacji @Override podczas nadpisywania
  • Zachęcaj do używania @Nullable, gdy pole lub metoda zwróci null
  • Skorzystaj ze specjalnych komentarzy do przyszłych prac i nie zapomnij zostawić odniesienia do siebie, aby inni wiedzieli, kto zadać pytanie Y zamiast zgadywać, usuwać je lub sprawdzać winę git, aby dowiedzieć się, kto je dodał. Niektóre środowiska IDE, takie jak Eclipse i IntelliJ, również pomagają w ich zestawieniu w celu zapewnienia łatwego dostępu oraz przypomnienia.
// FIXME (Raf): Aktywny komunikat opisuje, co należy zrobić
// TODO (Raf): Wykonalny komunikat opisuje, co należy zrobić

Końcową grą jest napisanie kodu, który ułatwi życie przyszłym autorom i opiekunom.

Gra końcowa

Inne odpowiednie materiały do ​​czytania

Lista odpowiednich artykułów, które są istotne dla pisania kodu, który jest czysty, dobrze skonstruowany, łatwy do odczytania i konserwacji. Jeśli chcesz przeczytać więcej, zdecydowanie zalecamy następujące

oraz kolejna dobra lista wskazówek dotyczących pisania czystego kodu