Styl kodu Java AOSP dla współtwórców

Style kodu na tej stronie to ścisłe zasady dotyczące dostarczania kodu Java do projektu Android Open Source Project (AOSP). Składki na platformie Android, które nie przestrzegają tych zasad ogólnie nie są akceptowane. Zdajemy sobie sprawę, że nie cały istniejący kod jest zgodny z tymi regułami, ale oczekujemy, że każdy nowy kod będzie zgodny. Zobacz Kodowanie w odniesieniu do przykładów wykorzystania terminologii i uniknięcia dla ekosystemu bardziej włącznie.

Bądź konsekwentny

Jedną z najprostszych zasad jest BĄDŹ KONSEKWENTNY. Jeśli edytujesz kod, poświęć kilka minut na przyjrzenie się otaczającemu kodowi i ustaleniu jego stylu. Jeśli to kod wykorzystuje przestrzenie wokół if klauzul, powinieneś też. Jeśli komentarze do kodu mają wokół siebie małe ramki z gwiazdkami, spraw, aby twoje komentarze również miały wokół siebie małe ramki z gwiazdkami.

Celem posiadania wskazówek dotyczących stylu jest posiadanie wspólnego słownictwa dotyczącego kodowania, aby czytelnicy mogli skoncentrować się na tym, co mówisz, a nie na tym, jak to mówisz. Przedstawiamy tutaj globalne zasady stylu, abyś znał słownictwo, ale ważny jest również styl lokalny. Jeśli kod, który dodajesz do pliku, wygląda drastycznie od istniejącego kodu wokół niego, wytrąca czytelników z rytmu, gdy go czytają. Staraj się tego unikać.

Zasady języka Java

Android przestrzega standardowych konwencji kodowania Java z dodatkowymi regułami opisanymi poniżej.

Nie ignoruj ​​wyjątków

Kuszące może być napisanie kodu, który ignoruje wyjątek, taki jak:

  void setServerPort(String value) {
      try {
          serverPort = Integer.parseInt(value);
      } catch (NumberFormatException e) { }
  }

Nie rób tego. Chociaż możesz myśleć, że Twój kod nigdy nie napotka tego błędu lub że nie jest ważne, aby go obsłużyć, ignorowanie tego typu wyjątku tworzy w kodzie miny, które ktoś inny może pewnego dnia wywołać. Musisz obsługiwać każdy wyjątek w swoim kodzie w sposób zgodny z zasadami; konkretna obsługa różni się w zależności od przypadku.

"Zawsze ktoś musi pustej klauzuli catch powinny one mieć przerażający uczucie. Na pewno są chwile, kiedy jest to rzeczywiście właściwa rzecz do zrobienia, ale przynajmniej trzeba myśleć o tym. W Java nie można uciec od dziwnego uczucia. "- James Gosling

Dopuszczalne alternatywy (w kolejności preferencji) to:

  • Zgłoś wyjątek do wywołującego metodę.
      void setServerPort(String value) throws NumberFormatException {
          serverPort = Integer.parseInt(value);
      }
    
  • Zgłoś nowy wyjątek, który jest odpowiedni dla Twojego poziomu abstrakcji.
      void setServerPort(String value) throws ConfigurationException {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new ConfigurationException("Port " + value + " is not valid.");
        }
      }
    
  • Obsługi błędu wdziękiem i zastąpić odpowiednią wartość w catch {} bloku.
      /** Set port. If value is not a valid number, 80 is substituted. */
    
      void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            serverPort = 80;  // default port for server
        }
      }
    
  • Złapać wyjątek i wyrzucić nową instancję RuntimeException . Jest to niebezpieczne, więc rób to tylko wtedy, gdy masz pewność, że jeśli wystąpi ten błąd, odpowiednią rzeczą do zrobienia jest awaria.
      /** Set port. If value is not a valid number, die. */
    
      void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new RuntimeException("port " + value " is invalid, ", e);
        }
      }
    
  • W ostateczności, jeśli masz pewność, że zignorowanie wyjątku jest właściwe, możesz go zignorować, ale musisz także skomentować, dlaczego, mając dobry powód.
    /** If value is not a valid number, original port number is used. */
    
    void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            // Method is documented to just ignore invalid user input.
            // serverPort will just be unchanged.
        }
    }
    

Nie łap wyjątków ogólnych

Kuszące może być lenistwo podczas łapania wyjątków i robienie czegoś takiego:

  try {
      someComplicatedIOFunction();        // may throw IOException
      someComplicatedParsingFunction();   // may throw ParsingException
      someComplicatedSecurityFunction();  // may throw SecurityException
      // phew, made it all the way
  } catch (Exception e) {                 // I'll just catch all exceptions
      handleError();                      // with one generic handler!
  }

Nie rób tego. W prawie wszystkich przypadkach, jest to nieodpowiednie do połowu ogólny Exception lub Throwable (najlepiej nie Throwable ponieważ zawiera Error wyjątki). Jest to niebezpieczne, ponieważ oznacza to, że wyjątki nigdy oczekiwane (w tym wyjątków uruchomieniowych jak ClassCastException ) złapany w obsługę błędów na poziomie aplikacji. Zasłania ona właściwości obsługi błędów w twoim kodzie, co oznacza, że ​​jeśli ktoś doda nowy typ wyjątku w wywoływanym kodzie, kompilator nie wskaże, że musisz inaczej obsłużyć błąd. W większości przypadków nie powinieneś obsługiwać różnych typów wyjątków w ten sam sposób.

Rzadkim wyjątkiem od tej reguły jest kod testowy i kod najwyższego poziomu, w którym chcesz wychwycić wszelkiego rodzaju błędy (aby zapobiec ich wyświetlaniu w interfejsie użytkownika lub aby utrzymać uruchomione zadanie wsadowe). W takich przypadkach można złapać rodzajowe Exception (lub Throwable ) i obsługi błędu odpowiednio. Zastanów się jednak dobrze, zanim to zrobisz i wstawiaj komentarze wyjaśniające, dlaczego jest to bezpieczne w tym kontekście.

Alternatywy do przechwytywania ogólnych wyjątków:

  • Złapać każdy wyjątek oddzielnie w ramach bloku wielu zatrzaskowej, np
    try {
        ...
    } catch (ClassNotFoundException | NoSuchMethodException e) {
        ...
    }
  • Refaktoryzuj swój kod, aby uzyskać bardziej szczegółową obsługę błędów, z wieloma blokami try. Oddziel IO od parsowania i obsługuj błędy osobno w każdym przypadku.
  • Zrzuć ponownie wyjątek. Wiele razy i tak nie musisz przechwytywać wyjątku na tym poziomie, po prostu pozwól, aby metoda go wyrzuciła.

Pamiętaj, że wyjątki są twoim przyjacielem! Kiedy kompilator skarży się, że nie łapiesz wyjątku, nie krzywij się. Uśmiechnij się! Kompilator właśnie ułatwił Ci wyłapywanie problemów w czasie wykonywania w Twoim kodzie.

Nie używaj finalizatorów

Finalizatory to sposób na wykonanie fragmentu kodu, gdy obiekt jest zbierany bezużytecznie. Chociaż finalizatory mogą być przydatne do czyszczenia (szczególnie zasobów zewnętrznych), nie ma gwarancji, kiedy zostanie wywołany finalizator (lub nawet, że zostanie wywołany w ogóle).

Android nie używa finalizatorów. W większości przypadków możesz zamiast tego użyć dobrej obsługi wyjątków. Jeśli koniecznie potrzebujesz finalizatora zdefiniuj close() metoda (lub podobne) oraz dokument dokładnie wtedy, że potrzeby metoda nazwać (patrz InputStream na przykład). W takim przypadku jest właściwe, ale nie wymagane, aby wydrukować krótki komunikat dziennika z finalizatora, o ile nie oczekuje się, że zaleje dzienniki.

W pełni kwalifikują się importy

Kiedy chcesz użyć klasy Bar z pakietu foo , istnieją dwa sposoby, aby go importować:

  • import foo.*;

    Potencjalnie zmniejsza liczbę instrukcji importu.

  • import foo.Bar;

    Widać wyraźnie, jakie klasy są używane, a kod jest bardziej czytelny dla opiekunów.

Zastosowanie import foo.Bar; do importowania całego kodu Androida. Wyraźne Wyjątkiem są dla standardowych bibliotek Javy ( java.util.* , java.io.* , itd.) I kod testów jednostkowych ( junit.framework.* ).

Zasady biblioteki Java

Istnieją konwencje dotyczące korzystania z bibliotek i narzędzi Java systemu Android. W niektórych przypadkach konwencja zmieniła się w istotny sposób i starszy kod może używać przestarzałego wzorca lub biblioteki. Podczas pracy z takim kodem można kontynuować istniejący styl. Jednak podczas tworzenia nowych komponentów nigdy nie używaj przestarzałych bibliotek.

Zasady stylu Java

Użyj standardowych komentarzy Javadoc

Każdy plik powinien mieć na górze deklarację dotyczącą praw autorskich, następnie deklarację pakietu i importu (każdy blok oddzielony pustą linią), a na końcu deklarację klasy lub interfejsu. W komentarzach Javadoc opisz, co robi klasa lub interfejs.

/*
 * Copyright 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.foo;

import android.os.Blah;
import android.view.Yada;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * Does X and Y and provides an abstraction for Z.
 */

public class Foo {
    ...
}

Każda klasa i nieszablonowe metody publiczne, które piszesz muszą zawierać komentarz Javadoc z co najmniej jedno zdanie opisujące co klasa lub metoda robi. To zdanie powinno zaczynać się od czasownika opisowego trzeciej osoby.

Przykłady

/** Returns the correctly rounded positive square root of a double value. */

static double sqrt(double a) {
    ...
}

lub

/**
 * Constructs a new String by converting the specified array of
 * bytes using the platform's default character encoding.
 */
public String(byte[] bytes) {
    ...
}

Nie trzeba pisać Javadoc dla błahych pobierania i ustawiania metod, takich jak setFoo() jeśli wszystkie swoje Javadoc powiedziałby to „zestawy Foo”. Jeśli metoda robi coś bardziej złożonego (takiego jak wymuszanie ograniczenia lub ma ważny efekt uboczny), musisz to udokumentować. Jeśli nie jest oczywiste, co oznacza właściwość „Foo”, należy to udokumentować.

Każda metoda, którą napiszesz, publiczna lub inna, skorzysta na Javadoc. Metody publiczne są częścią interfejsu API i dlatego wymagają dokumentacji Javadoc. Android nie wymusza specyficzny styl pisania komentarzy dla Javadoc, ale należy postępować zgodnie z instrukcjami Jak napisać Doc Komentarze dla Javadoc narzędzia .

Napisz krótkie metody

Jeśli to możliwe, staraj się, aby metody były małe i skoncentrowane. Zdajemy sobie sprawę, że długie metody są czasami odpowiednie, więc nie ma sztywnych ograniczeń co do długości metody. Jeśli metoda przekracza 40 linii, zastanów się, czy można ją podzielić bez szkody dla struktury programu.

Zdefiniuj pola w standardowych miejscach

Zdefiniuj pola u góry pliku lub bezpośrednio przed metodami, które ich używają.

Ogranicz zakres zmiennych

Ogranicz zakres zmiennych lokalnych do minimum. Zwiększa to czytelność i łatwość konserwacji kodu oraz zmniejsza prawdopodobieństwo błędu. Zadeklaruj każdą zmienną w najbardziej wewnętrznym bloku, który obejmuje wszystkie zastosowania zmiennej.

Zadeklaruj zmienne lokalne w miejscu, w którym są one używane po raz pierwszy. Prawie każda deklaracja zmiennej lokalnej powinna zawierać inicjator. Jeśli nie masz jeszcze wystarczających informacji, aby sensownie zainicjować zmienną, odłóż deklarację, aż to zrobisz.

Wyjątkiem są instrukcje try-catch. Jeśli zmienna jest inicjowana wartością zwracaną metody, która zgłasza sprawdzony wyjątek, musi być zainicjowana wewnątrz bloku try. Jeśli wartość musi być użyta poza blokiem try, to musi być zadeklarowana przed blokiem try, gdzie nie można jej jeszcze sensownie zainicjować:

// Instantiate class cl, which represents some sort of Set

Set s = null;
try {
    s = (Set) cl.newInstance();
} catch(IllegalAccessException e) {
    throw new IllegalArgumentException(cl + " not accessible");
} catch(InstantiationException e) {
    throw new IllegalArgumentException(cl + " not instantiable");
}

// Exercise the set
s.addAll(Arrays.asList(args));

Możesz jednak nawet uniknąć tego przypadku, umieszczając blok try-catch w metodzie:

Set createSet(Class cl) {
    // Instantiate class cl, which represents some sort of Set
    try {
        return (Set) cl.newInstance();
    } catch(IllegalAccessException e) {
        throw new IllegalArgumentException(cl + " not accessible");
    } catch(InstantiationException e) {
        throw new IllegalArgumentException(cl + " not instantiable");
    }
}

...

// Exercise the set
Set s = createSet(cl);
s.addAll(Arrays.asList(args));

Zadeklaruj zmienne pętli w samej instrukcji for, chyba że istnieje ważny powód, aby zrobić inaczej:

for (int i = 0; i < n; i++) {
    doSomething(i);
}

oraz

for (Iterator i = c.iterator(); i.hasNext(); ) {
    doSomethingElse(i.next());
}

Zamów wyciągi importowe

Kolejność wyciągów importowych jest następująca:

  1. Import z Androida
  2. Przywóz z osobami trzecimi ( com , junit , net , org )
  3. java i javax

Aby dokładnie dopasować ustawienia IDE, importy powinny wyglądać następująco:

  • Alfabetycznie w ramach każdej grupy, z wielkimi literami przed małymi literami (na przykład Z przed a)
  • Oddzielone pustą linią pomiędzy każdej większej grupy ( android , com , junit , net , org , java , javax )

Początkowo nie było wymagań dotyczących stylu w kolejności, co oznaczało, że IDE albo zawsze zmieniały kolejność, albo programiści IDE musieli wyłączyć funkcje automatycznego zarządzania importem i ręcznie obsługiwać importy. Uznano to za złe. Kiedy zapytano o styl Java, preferowane style bardzo się różniły i sprowadzało się to do Androida, który musiał po prostu „wybrać kolejność i być spójnym”. Wybraliśmy więc styl, zaktualizowaliśmy przewodnik po stylu i sprawiliśmy, że IDE go przestrzegają. Spodziewamy się, że gdy użytkownicy IDE pracują nad kodem, importy we wszystkich pakietach będą pasować do tego wzorca bez dodatkowego wysiłku inżynierskiego.

Wybraliśmy ten styl tak, aby:

  • Przywóz, że ludzie chcą wyglądać na początku wydają się być na górze ( android ).
  • Przywóz, że ludzie chcą wyglądać przynajmniej wydają się być na dole ( java ).
  • Ludzie mogą z łatwością podążać za tym stylem.
  • IDE mogą podążać za stylem.

Umieść importy statyczne nad wszystkimi innymi importami zamówionymi w taki sam sposób, jak importy zwykłe.

Użyj spacji do wcięć

Używamy czterech (4) wcięć spacji dla bloków i nigdy tabulatorów. W razie wątpliwości bądź spójny z otaczającym kodem.

Używamy ośmiu (8) wcięć spacji do zawijania linii, w tym wywołań funkcji i przypisania.

Zalecana

Instrument i =
        someLongExpression(that, wouldNotFit, on, one, line);

Niepolecane

Instrument i =
    someLongExpression(that, wouldNotFit, on, one, line);

Przestrzegaj konwencji nazewnictwa pól

  • Niepubliczną, non-statyczne nazwy pól zacząć m .
  • Statyczne nazwy pól zacząć s .
  • Inne pola zaczynają się od małej litery.
  • Statycznych pól Ostateczne publiczne (stałe) są ALL_CAPS_WITH_UNDERSCORES .

Na przykład:

public class MyClass {
    public static final int SOME_CONSTANT = 42;
    public int publicField;
    private static MyClass sSingleton;
    int mPackagePrivate;
    private int mPrivate;
    protected int mProtected;
}

Użyj standardowego stylu klamry

Umieść nawiasy klamrowe w tym samym wierszu co kod przed nimi, a nie w osobnym wierszu:

class MyClass {
    int func() {
        if (something) {
            // ...
        } else if (somethingElse) {
            // ...
        } else {
            // ...
        }
    }
}

Wymagamy nawiasów klamrowych wokół instrukcji warunkowych. Wyjątek: Jeśli cały warunek (stan i ciało) mieści się w jednej linii, możesz (ale nie musisz) umieścić to wszystko w jednej linii. Na przykład jest to dopuszczalne:

if (condition) {
    body();
}

i to jest dopuszczalne:

if (condition) body();

ale to jest nie do przyjęcia:

if (condition)
    body();  // bad!

Ogranicz długość linii

Każda linia tekstu w kodzie powinna mieć maksymalnie 100 znaków. Podczas gdy wiele dyskusji otoczyła tę regułę, że decyzja pozostaje 100 znaków to maksymalna z następującymi wyjątkami:

  • Jeśli wiersz komentarza zawiera przykładowe polecenie lub dosłowny adres URL dłuższy niż 100 znaków, wiersz ten może być dłuższy niż 100 znaków, aby ułatwić wycinanie i wklejanie.
  • Linie importu mogą przekroczyć limit, ponieważ ludzie rzadko je widzą (ułatwia to również pisanie narzędzi).

Użyj standardowych adnotacji Java

Adnotacje powinny poprzedzać inne modyfikatory dla tego samego elementu języka. Proste adnotacje Marker (na przykład @Override ), mogą być wymienione na tej samej linii z elementem języka. Jeśli istnieje wiele adnotacji lub adnotacji sparametryzowanych, wymień je po jednym w wierszu w kolejności alfabetycznej.

Standardowe praktyki Androida dotyczące trzech predefiniowanych adnotacji w Javie to:

  • Za pomocą @Deprecated adnotacji gdy użycie opatrzony elementu nie jest zalecane. Jeśli używasz @Deprecated adnotacji, należy również mieć @deprecated tag Javadoc i należy go wymienić alternatywną realizację. Ponadto, należy pamiętać, że @Deprecated metoda nadal ma pracy. Jeśli widzisz stary kod, który ma @deprecated tag Javadoc, dodać @Deprecated adnotacji.
  • Użyj @Override adnotacji gdy metoda nadpisuje deklaracji lub implementacji z nadklasy. Na przykład, jeśli używasz @inheritdocs tag javadoc, a wywodzą się z klasy (nie interfejsu), należy również adnotacji, że metoda zastępuje metodę klasy nadrzędnej.
  • Użyj @SuppressWarnings adnotacji tylko w warunkach, w których nie da się wyeliminować ostrzeżenie. Jeśli ostrzeżenie przechodzi ten test „niemożliwe do wyeliminowania”, to @SuppressWarnings adnotacji muszą być stosowane, aby zapewnić, że wszystkie ostrzeżenia odzwierciedlać rzeczywiste problemy w kodzie.

    Kiedy @SuppressWarnings adnotacja jest konieczne, musi być poprzedzona TODO komentarzu który wyjaśnia „niemożliwe do wyeliminowania” warunek. Zwykle identyfikuje to naruszającą klasę, która ma niewygodny interfejs. Na przykład:

    // TODO: The third-party class com.third.useful.Utility.rotate() needs generics
    @SuppressWarnings("generic-cast")
    List<String> blix = Utility.rotate(blax);
    

    Kiedy @SuppressWarnings wymagana jest adnotacja, byłaby kodu do izolowania elementów programowych, gdzie ma zastosowanie adnotacji.

Traktuj akronimy jako słowa

Traktuj akronimy i skróty jako słowa w nazewnictwie zmiennych, metod i klas, aby nazwy były bardziej czytelne:

Dobry Zły
XmlHttpRequest Żądanie XMLHTTP
getCustomerId zdobądź IDKlienta
klasa HTML klasa HTML
URL ciągu Ciąg URL
długi identyfikator długi identyfikator

Ponieważ zarówno JDK, jak i kod Androida są niespójne wokół akronimów, praktycznie niemożliwe jest zachowanie spójności z otaczającym kodem. Dlatego zawsze traktuj akronimy jak słowa.

Użyj komentarzy TODO

Zastosowanie TODO komentarzy do kodu, który jest tymczasowy, rozwiązania krótkoterminowego lub wystarczająco dobry, ale nie doskonały. Uwagi te powinny zawierać ciąg TODO we wszystkich czapki, a następnie dwukropek:

// TODO: Remove this code after the UrlTable2 has been checked in.

oraz

// TODO: Change this to use a flag instead of a constant.

Jeśli TODO ma postać „W terminie w przyszłości coś zrobić” upewnij się, że albo zawierają datę specyficzny ( „poprawkę listopada 2005”) lub wydarzenie szczególne ( „Usuń ten kod po wszystkie miksery produkcyjne zrozumieć protokół V7.” ).

Loguj oszczędnie

Chociaż rejestrowanie jest konieczne, ma negatywny wpływ na wydajność i traci swoją użyteczność, jeśli nie jest odpowiednio zwięzłe. Urządzenia rejestrujące zapewniają pięć różnych poziomów rejestrowania:

  • ERROR : używany, gdy coś działo się śmiertelny, czyli coś, co będzie miało konsekwencje widoczne dla użytkownika i nie będzie można odzyskać bez usuwania niektórych danych, odinstalowywanie aplikacji, wycierając partycje z danymi, lub reflashing całego urządzenia (lub gorzej). Ten poziom jest zawsze rejestrowany. Problemy, które uzasadniają pewne logowania na ERROR poziomie są dobrymi kandydatami być zgłaszane do serwera statystyki-gromadzącej.
  • WARNING : używany, gdy coś poważnego i nieoczekiwanego, to jest coś, co będzie miało dla użytkownika widoczne skutki, ale prawdopodobnie będzie zwrotowi bez utraty danych, wykonując pewne wyraźne działanie, od czekania lub ponownym uruchomieniu aplikacji przez całą drogę do ponownego pobrania nową wersję aplikacji lub ponowne uruchomienie urządzenia. Ten poziom jest zawsze rejestrowany. Problemy, które uzasadniają logowaniem na WARNING poziomie może być również uznane za zgłoszenie do serwera statystyki-gromadzącej.
  • INFORMATIVE : Użyj, aby pamiętać, że wydarzyło się coś ciekawego, to znaczy, gdy sytuacja zostanie wykryte, że może mieć szeroki wpływ, choć niekoniecznie jest błąd. Taki stan powinien być rejestrowany tylko przez moduł, który uważa, że ​​jest najbardziej autorytatywny w tej domenie (aby uniknąć podwójnego rejestrowania przez nieautorytatywne komponenty). Ten poziom jest zawsze rejestrowany.
  • DEBUG : Służy do dalszego noty, co się dzieje na urządzeniu, które mogą być istotne dla zbadania i debugowania nieoczekiwanych zachowań. Rejestruj tylko to, co jest potrzebne, aby zebrać wystarczającą ilość informacji o tym, co dzieje się z Twoim komponentem. Jeśli dzienniki debugowania dominują w dzienniku, należy użyć pełnego rejestrowania.

    Poziom ten jest rejestrowany nawet na uwolnienie buduje, a wymagane jest być otoczony if (LOCAL_LOG) lub if LOCAL_LOGD) blok, gdzie LOCAL_LOG[D] jest zdefiniowany w klasie lub podskładnika tak, że istnieje możliwość, aby wyłączyć wszystkie takie rejestrowanie . W związku z tym nie może być włączony w układ logiczny if (LOCAL_LOG) bloku. Cały budynek ciąg dla dziennika musi być także umieszczony wewnątrz if (LOCAL_LOG) bloku. Nie byłaby połączenia wylogowaniu do wywołania metody, jeśli to będzie powodować ciąg budynku odbywać się poza granicami if (LOCAL_LOG) bloku.

    Jest jakiś kod, który ciągle mówi if (localLOGV) . Jest to również uważane za dopuszczalne, chociaż nazwa jest niestandardowa.

  • VERBOSE : Służy do wszystkiego innego. Poziom ten jest rejestrowany tylko na debug buduje i powinny być otoczone if (LOCAL_LOGV) bloku (lub odpowiednik), tak, że może być skompilowany z domyślnie. Wszelkie budynek łańcuch jest usuwany z uwalniania buduje i musi pojawić się wewnątrz if (LOCAL_LOGV) bloku.

Uwagi

  • W ramach danego modułu, inne niż na VERBOSE poziomie błędu powinny być zgłaszane tylko raz, jeśli to możliwe. W pojedynczym łańcuchu wywołań funkcji w module tylko najbardziej wewnętrzna funkcja powinna zwracać błąd, a wywołujący w tym samym module powinni dodać trochę rejestrowania tylko wtedy, gdy znacząco pomaga to wyizolować problem.
  • W łańcuchu modułów, inne niż na VERBOSE poziomie, gdy moduł niższy poziom wykrywa nieprawidłowe dane pochodzące z modułu nadrzędnego, moduł niższy poziom powinien jedynie zalogować tę sytuację do DEBUG dzienniku, i tylko wtedy, gdy rejestrowanie zapewnia informacje, które nie są dostępne dla dzwoniącego w inny sposób. W szczególności nie ma potrzeby rejestrowania sytuacji, w których zgłaszany jest wyjątek (wyjątek powinien zawierać wszystkie istotne informacje) lub gdy jedyna rejestrowana informacja jest zawarta w kodzie błędu. Jest to szczególnie ważne w interakcji pomiędzy systemem i aplikacjami oraz warunków spowodowanych przez aplikacje innych firm, które są prawidłowo obsługiwane przez ramy nie powinny wywołać zalogowaniu wyższa niż DEBUG poziomie. Jedyne sytuacje, które powinny wywołać rejestrowanie przy INFORMATIVE poziomie lub wyższym jest, gdy moduł lub aplikacja wykryje błąd w swoim własnym poziomie lub pochodzących z niższego poziomu.
  • Gdy sytuacja, która normalnie uzasadniałaby pewne rejestrowanie, może wystąpić wiele razy, dobrym pomysłem może być zaimplementowanie mechanizmu ograniczającego szybkość, aby zapobiec przepełnieniu dzienników wieloma zduplikowanymi kopiami tych samych (lub bardzo podobnych) informacji.
  • Utraty łączności sieciowej są uważane za powszechne i są w pełni oczekiwane i nie powinny być rejestrowane bezpodstawnie. Utrata łączności sieciowej, która ma konsekwencje w aplikacji powinny być rejestrowane w DEBUG lub VERBOSE poziomie (w zależności od tego, czy konsekwencje są poważne i nieoczekiwane tyle wystarczy być zalogowany kompilacji uwalnianiu).
  • Posiadanie pełnego systemu plików w systemie plików, który jest dostępny dla aplikacji innych firm lub w ich imieniu, nie powinno być rejestrowane na poziomie wyższym niż INFORMATIVE.
  • Nieprawidłowe dane pochodzące z dowolnego niezaufanych źródeł (w tym dowolnego pliku na współdzielonej pamięci masowej lub dane pochodzące z wykorzystaniem połączenia sieciowego) jest uważany za oczekiwaniami i nie powinny powodować żadnych rejestrowanie na poziomie wyższym niż DEBUG kiedy jest wykrywany za nieważne (a nawet wtedy rejestrowanie powinna być jak najbardziej ograniczona).
  • Przy stosowaniu na String obiektów The + operator niejawnie tworzy StringBuilder instancję domyślny rozmiar bufora (16 znaków) i potencjalnie innych tymczasowych String obiektów. Tak jawnie tworzyć StringBuilder obiektów nie jest droższe niż opierając się na domyślnym + operatora (a może być dużo bardziej wydajne). Należy pamiętać, że kod, który wywołuje Log.v() jest kompilowany i wykonywany na uwolnienie buduje, w tym budowę ciągów, nawet jeśli dzienniki nie są odczytywane.
  • Każde logowanie, które ma być odczytywane przez inne osoby i dostępne w kompilacjach wydań, powinno być zwięzłe, ale nie zagadkowe i powinno być zrozumiałe. Obejmuje to wszystkie działania związane z rejestrowania DEBUG poziomie.
  • Jeśli to możliwe, loguj się w jednym wierszu. Dopuszczalne są linie o długości do 80 lub 100 znaków. Jeśli to możliwe, unikaj długości dłuższych niż około 130 lub 160 znaków (łącznie z długością tagu).
  • Jeśli zalogowaniu raporty sukcesów, nigdy nie używać go na poziomie wyższym niż VERBOSE .
  • Jeśli używasz tymczasową rejestrację aby zdiagnozować problem, który trudno odtworzyć, zachować go w DEBUG lub VERBOSE poziomie i dołączyć go czy bloków, które pozwalają na wyłączenie go w czasie kompilacji.
  • Uważaj na przecieki bezpieczeństwa w dzienniku. Unikaj rejestrowania prywatnych informacji. W szczególności unikaj logowania informacji o chronionych treściach. Jest to szczególnie ważne podczas pisania kodu frameworka, ponieważ nie jest łatwo z góry wiedzieć, które informacje będą, a jakie nie będą informacjami prywatnymi lub chronionymi treściami.
  • Nigdy nie należy używać System.out.println() (lub printf() do natywnego kodu). System.out i System.err uzyskać przekierowany do /dev/null , więc twoje wypowiedzi drukujące mają żadnych widocznych efektów. Jednak całe budowanie ciągów, które ma miejsce w przypadku tych wywołań, nadal jest wykonywane.
  • Złota zasada rejestrowania polega na tym, że Twoje dzienniki nie mogą niepotrzebnie wypychać innych dzienników z bufora, tak jak inni nie mogą wypychać Twoich.

Zasady stylu Javatestów

Postępuj zgodnie z konwencjami nazewnictwa metod testowych i użyj podkreślenia, aby oddzielić to, co jest testowane, od konkretnego testowanego przypadku. Ten styl ułatwia sprawdzenie, które przypadki są testowane. Na przykład:

testMethod_specificCase1 testMethod_specificCase2

void testIsDistinguishable_protanopia() {
    ColorMatcher colorMatcher = new ColorMatcher(PROTANOPIA)
    assertFalse(colorMatcher.isDistinguishable(Color.RED, Color.BLACK))
    assertTrue(colorMatcher.isDistinguishable(Color.X, Color.Y))
}