Style kodu na tej stronie są ścisłymi regułami dotyczącymi wnoszenia kodu Java do Android Open Source Project (AOSP). Prace na platformie Android, które nie przestrzegają tych zasad, nie są akceptowane. Zdajemy sobie sprawę, że nie wszystkie istniejące kody przestrzegają tych zasad, ale oczekujemy, że wszystkie nowe kody będą zgodne z tymi zasadami. Zobacz Coding with Respect dla przykładów terminologii do użycia i unikania dla bardziej inkluzywnego ekosystemu.
- Bądź konsekwentny
- Zasady języka Java
- Nie ignoruj wyjątków
- Nie łap ogólnych wyjątków
- Nie używaj finalizatorów
- Fully qualify imports
- Reguły biblioteki Java
- Zasady stylu Java
- Pisz krótkie metody
- Zdefiniuj pola w standardowych miejscach
- Ograniczyć zakres zmiennych
- Order import statements
- Use spaces for indentation
- Follow field naming conventions
- Use standard brace style
- Limit line length
- Używaj standardowych adnotacji Java
- Treat acronyms as words
- Loguj oszczędnie
- Wskazówki
- Zasady stylu testowania
Bądź konsekwentny
Jedną z najprostszych zasad jest BYĆ KONSEKWENTNYM. Jeśli edytujesz kod, poświęć kilka minut, aby spojrzeć na otaczający kod i określić jego styl. Jeśli tamten kod używa spacji wokół klauzul if
, Ty też powinieneś to zrobić. Jeśli komentarze do kodu mają małe pudełka z gwiazdkami wokół nich, spraw, aby twoje komentarze również miały małe pudełka z gwiazdkami wokół nich.
Celem posiadania wytycznych dotyczących stylu jest posiadanie wspólnego słownika kodowania, aby czytelnicy mogli skupić się na tym, co mówisz, a nie na tym, jak to mówisz. Przedstawiamy tutaj globalne zasady stylu, abyś znał słownictwo, ale lokalny styl jest również ważny. Jeśli kod, który dodajesz do pliku, wygląda drastycznie inaczej niż istniejący wokół niego kod, wytrąca to czytelników z rytmu podczas czytania. Postaraj się tego uniknąć.
Zasady języka Java
Android podąża za standardowymi konwencjami kodowania Java z dodatkowymi zasadami opisanymi poniżej.
Nie ignoruj wyjątków
Może być kuszące 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 stanu błędu lub że nie jest ważne, aby go obsłużyć, ignorowanie tego typu wyjątków tworzy miny w twoim kodzie, które ktoś inny może kiedyś wywołać. Musisz obsłużyć każdy wyjątek w swoim kodzie w sposób zasadniczy; konkretna obsługa różni się w zależności od przypadku.
„Za każdym razem, gdy ktoś ma pustą klauzulę catch, powinien mieć przerażające uczucie. Zdecydowanie są czasy, kiedy jest to faktycznie właściwa rzecz do zrobienia, ale przynajmniej musisz o tym pomyśleć. W Javie nie możesz uciec od tego przerażającego uczucia.” – James Gosling
Akceptowalne alternatywy (w kolejności preferencji) to:
- Rzuć wyjątek do osoby wywołującej twoją metodę.
void setServerPort(String value) throws NumberFormatException { serverPort = Integer.parseInt(value); }
- Rzuć 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łuż błąd z wdziękiem i zastąp odpowiednią wartość w bloku
catch {}
/** 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łap wyjątek i rzuć nową instancję
RuntimeException
. Jest to niebezpieczne, więc rób to tylko wtedy, gdy jesteś pewien, że jeśli wystąpi ten błąd, właściwą rzeczą do zrobienia jest crash./** 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 jesteś pewien, że ignorowanie wyjątku jest właściwe, wtedy możesz go zignorować, ale musisz również skomentować dlaczego z dobrym powodem.
/** 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 ogólnych wyjątków
Może być kuszące, aby być leniwym podczas łapania wyjątków i zrobić coś 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 niewłaściwe jest łapanie generycznych wyjątków Exception
lub Throwable
(najlepiej nie Throwable
ponieważ zawiera wyjątki Error
). Jest to niebezpieczne, ponieważ oznacza to, że wyjątki, których nigdy się nie spodziewałeś (w tym wyjątki runtime, takie jak ClassCastException
) zostają złapane w obsłudze błędów na poziomie aplikacji. Zaciemnia właściwości obsługi błędów twojego kodu, co oznacza, że jeśli ktoś doda nowy typ wyjątku w kodzie, który wywołujesz, kompilator nie zwróci uwagi, że musisz obsłużyć błąd inaczej. 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, gdzie chcesz wyłapać wszystkie rodzaje błędów (aby zapobiec ich wyświetlaniu w UI, lub aby utrzymać działanie zadania wsadowego). W takich przypadkach możesz złapać generyczny Exception
(lub Throwable
) i odpowiednio obsłużyć błąd. Zastanów się jednak dobrze zanim to zrobisz i umieść w komentarzach wyjaśnienie, dlaczego jest to bezpieczne w tym kontekście.
Alternatywy dla łapania ogólnych wyjątków:
- Łapanie każdego wyjątku osobno jako część bloku multi-catch, na przykład:
try { ...} catch (ClassNotFoundException | NoSuchMethodException e) { ...}
- Zmodernizuj swój kod tak, aby miał bardziej szczegółową obsługę błędów, z wieloma blokami try. Rozdziel IO od parsowania i obsługuj błędy oddzielnie w każdym przypadku.
- Wyrzuć wyjątek. Wiele razy nie musisz łapać wyjątku na tym poziomie, po prostu pozwól metodzie go rzucić.
Pamiętaj, że wyjątki są twoim przyjacielem! Kiedy kompilator narzeka, że nie łapiesz wyjątku, nie złorzecz. Uśmiechnij się! Kompilator właśnie ułatwił ci wychwycenie problemów runtime w twoim kodzie.
Nie używaj finalizatorów
Finalizatory są sposobem na wykonanie fragmentu kodu, gdy obiekt jest odśmiecany. Podczas gdy finalizatory mogą być przydatne do sprzątania (szczególnie zewnętrznych zasobów), nie ma gwarancji, kiedy finalizator zostanie wywołany (lub nawet, że w ogóle zostanie wywołany).
Android nie używa finalizatorów. W większości przypadków można zamiast nich użyć dobrej obsługi wyjątków. If you absolutely need a finalizer, define a close()
method (or the like) and document exactly when that method needs to be called (see InputStream for an example). In this case, it’s appropriate but not required to print a short log message from the finalizer, as long as it’s not expected to flood the logs.
Fully qualify imports
When you want to use class Bar
from package foo
, there are two possible ways to import it:
-
import foo.*;
Potentially reduces the number of import statements.
-
import foo.Bar;
Makes it obvious what classes are used and the code is more readable for maintainers.
Use import foo.Bar;
for importing all Android code. An explicit exception is made for Java standard libraries (java.util.*
java.io.*
, etc.) and unit test code (junit.framework.*
).
Reguły biblioteki Java
Istnieją konwencje używania bibliotek i narzędzi Java systemu Android. W niektórych przypadkach konwencja zmieniła się w istotny sposób, a starszy kod może używać przestarzałego wzorca lub biblioteki. Podczas pracy z takim kodem, dobrze jest kontynuować istniejący styl. Jednak podczas tworzenia nowych komponentów, nigdy nie należy używać przestarzałych bibliotek.
Zasady stylu Java
Każdy plik powinien mieć na górze deklarację praw autorskich, następnie deklaracje package i import (każdy blok oddzielony pustą linią), a na końcu deklarację klasy lub interfejsu. W komentarzach Javadoc należy opisać, co dana klasa lub interfejs robi.
/* * Copyright 2020 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 nietrywialna metoda publiczna, którą napiszesz, musi zawierać komentarz Javadoc z co najmniej jednym zdaniem opisującym, co klasa lub metoda robi. Zdanie to powinno zaczynać się od czasownika opisowego w trzeciej osobie.
Przykłady
/** Returns the correctly rounded positive square root of a double value. */static double sqrt(double a) { ...}
albo
/** * Constructs a new String by converting the specified array of * bytes using the platform's default character encoding. */public String(byte bytes) { ...}
Nie musisz pisać Javadoc dla trywialnych metod get i set, takich jak setFoo()
jeśli wszystko co twój Javadoc powie to „ustawia Foo”. Jeśli metoda robi coś bardziej złożonego (takiego jak egzekwowanie ograniczeń lub ma ważny efekt uboczny), to musisz to udokumentować. Jeśli nie jest oczywiste, co oznacza właściwość „Foo”, powinieneś to udokumentować.
Każda metoda, którą piszesz, publiczna lub inna, skorzystałaby z Javadoc. Metody publiczne są częścią API i dlatego wymagają Javadoc. Android nie narzuca określonego stylu pisania komentarzy Javadoc, ale powinieneś postępować zgodnie z instrukcjami w How to Write Doc Comments for the Javadoc Tool.
Pisz krótkie metody
Gdy to możliwe, trzymaj metody małe i skoncentrowane. Zdajemy sobie sprawę, że długie metody są czasami odpowiednie, więc nie ma twardego limitu na ich długość. Jeśli metoda przekracza 40 linii lub więcej, zastanów się, czy można ją rozbić bez szkody dla struktury programu.
Zdefiniuj pola w standardowych miejscach
Zdefiniuj pola albo na górze pliku, albo bezpośrednio przed metodami, które z nich korzystają.
Ograniczyć zakres zmiennych
Zmniejszyć zakres zmiennych lokalnych do minimum. Zwiększa to czytelność i łatwość utrzymania kodu oraz zmniejsza prawdopodobieństwo wystąpienia błędu. Deklaruj każdą zmienną w najbardziej wewnętrznym bloku, który zawiera wszystkie użycia tej zmiennej.
Deklaruj zmienne lokalne w miejscu, w którym są one po raz pierwszy używane. Prawie każda deklaracja zmiennej lokalnej powinna zawierać inicjalizator. Jeśli nie masz jeszcze wystarczającej ilości informacji, aby sensownie zainicjować zmienną, odłóż deklarację do czasu, aż to zrobisz.
Wyjątkiem są instrukcje try-catch. Jeśli zmienna jest zainicjalizowana wartością zwracaną przez metodę, która rzuca sprawdzany wyjątek, musi być zainicjowana wewnątrz bloku try. If the value must be used outside of the try block, then it must be declared before the try block, where it can’t yet be sensibly initialized:
// Instantiate class cl, which represents some sort of SetSet 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 sets.addAll(Arrays.asList(args));
However, you can even avoid this case by encapsulating the try-catch block in a method:
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 setSet s = createSet(cl);s.addAll(Arrays.asList(args));
Declare loop variables in the for statement itself unless there’s a compelling reason to do otherwise:
for (int i = 0; i < n; i++) { doSomething(i);}
and
for (Iterator i = c.iterator(); i.hasNext(); ) { doSomethingElse(i.next());}
Order import statements
The ordering of import statements is:
- Android imports
- Imports from third parties (
com
junit
net
org
) -
java
andjavax
To exactly match the IDE settings, the imports should be:
- Alfabetyczny w obrębie każdej grupy, z dużymi literami przed małymi literami (na przykład, Z przed a)
- Oddzielony pustą linią pomiędzy każdą większą grupą (
android
com
junit
net
org
java
javax
)
Pierwotnie nie było żadnych wymagań dotyczących stylu w zakresie zamawiania, co oznaczało, że IDE zawsze zmieniały kolejność lub programiści IDE musieli wyłączyć funkcje automatycznego zarządzania importem i ręcznie utrzymywać importy. Zostało to uznane za złe. Kiedy zapytano o styl Java, preferowane style różniły się diametralnie i sprowadzało się to do tego, że Android musi po prostu „wybrać sposób zamawiania i być konsekwentny.” Wybraliśmy więc styl, zaktualizowaliśmy przewodnik po stylach i sprawiliśmy, że IDE będą go przestrzegać. Oczekujemy, że w miarę jak użytkownicy IDE będą pracować nad kodem, importy we wszystkich pakietach będą pasować do tego wzorca bez dodatkowego wysiłku inżynierskiego.
We chose this style such that:
- The imports that people want to look at first tend to be at the top (
android
). - The imports that people want to look at least tend to be at the bottom (
java
). - Humans can easily follow the style.
- IDEs can follow the style.
Put static imports above all the other imports ordered the same way as regular imports.
Use spaces for indentation
We use four (4) space indents for blocks and never tabs. When in doubt, be consistent with the surrounding code.
We use eight (8) space indents for line wraps, including function calls and assignments.
Recommended
Instrument i = someLongExpression(that, wouldNotFit, on, one, line);
Not recommended
Instrument i = someLongExpression(that, wouldNotFit, on, one, line);
Follow field naming conventions
- Non-public, non-static field names start with
m
. - Static field names start with
s
. - Other fields start with a lower case letter.
- Public static final fields (constants) are
ALL_CAPS_WITH_UNDERSCORES
.
For example:
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;}
Use standard brace style
Put braces on the same line as the code before them, not on their own line:
class MyClass { int func() { if (something) { // ... } else if (somethingElse) { // ... } else { // ... } }}
We require braces around the statements for a conditional. Exception: If the entire conditional (the condition and the body) fit on one line, you may (but are not obligated to) put it all on one line. For example, this is acceptable:
if (condition) { body();}
and this is acceptable:
if (condition) body();
but this is not acceptable:
if (condition) body(); // bad!
Limit line length
Each line of text in your code should be at most 100 characters long. While much discussion has surrounded this rule, the decision remains that 100 characters is the maximum with the following exceptions:
- Jeśli linia komentarza zawiera przykładowe polecenie lub dosłowny adres URL dłuższy niż 100 znaków, linia ta może być dłuższa niż 100 znaków dla ułatwienia wycinania i wklejania.
- Linie importu mogą przekroczyć limit, ponieważ ludzie rzadko je widzą (to również upraszcza pisanie narzędzi).
Używaj standardowych adnotacji Java
Adnotacje powinny poprzedzać inne modyfikatory dla tego samego elementu języka. Proste adnotacje znacznikowe (na przykład, @Override
) mogą być wymienione w tej samej linii z elementem języka. Jeśli istnieje wiele adnotacji lub parametryzowanych adnotacji, wymień je po jednej na linię w porządku alfabetycznym.
Standardowe praktyki Androida dla trzech predefiniowanych adnotacji w Javie to:
- Użyj adnotacji
@Deprecated
zawsze wtedy, gdy użycie adnotowanego elementu jest odradzane. Jeśli używasz adnotacji@Deprecated
, musisz również mieć tag@deprecated
Javadoc i powinien on wymieniać alternatywną implementację. Ponadto pamiętaj, że metoda@Deprecated
wciąż ma działać. Jeśli widzisz stary kod, który ma@deprecated
Javadoc tag, dodaj adnotację@Deprecated
. - Użyj adnotacji
@Override
za każdym razem, gdy metoda nadpisuje deklarację lub implementację z nadklasy. Na przykład, jeśli używasz znacznika Javadoc@inheritdocs
i wywodzisz się z klasy (nie z interfejsu), musisz również dodać adnotację, że metoda zastępuje metodę klasy nadrzędnej. - Użyj adnotacji
@SuppressWarnings
tylko w okolicznościach, w których niemożliwe jest wyeliminowanie ostrzeżenia. If a warning passes this „impossible to eliminate” test, the@SuppressWarnings
annotation must be used, to ensure that all warnings reflect actual problems in the code.When a
@SuppressWarnings
annotation is necessary, it must be prefixed with aTODO
comment that explains the „impossible to eliminate” condition. This normally identifies an offending class that has an awkward interface. Na przykład:// TODO: The third-party class com.third.useful.Utility.rotate() needs generics@SuppressWarnings("generic-cast")List<String> blix = Utility.rotate(blax);
When a
@SuppressWarnings
annotation is required, refactor the code to isolate the software elements where the annotation applies.
Treat acronyms as words
Treat acronyms and abbreviations as words in naming variables, methods, and classes to make names more readable:
Good | Bad |
---|---|
XmlHttpRequest | XMLHTTPRequest |
getCustomerId | getCustomerID |
class Html | class HTML |
String url | String URL |
long id | long ID |
As both the JDK and the Android code bases are inconsistent around acronyms, it’s virtually impossible to be consistent with the surrounding code. Therefore, always treat acronyms as words.
Use TODO
comments for code that is temporary, a short-term solution, or good enough but not perfect. These comments should include the string TODO
in all caps, followed by a colon:
// TODO: Remove this code after the UrlTable2 has been checked in.
i
// TODO: Change this to use a flag instead of a constant.
Jeżeli twój TODO
ma postać „W przyszłym terminie zrób coś”, upewnij się, że albo zawiera konkretną datę („Napraw do listopada 2005”), albo konkretne wydarzenie („Usuń ten kod po tym, jak wszystkie miksery produkcyjne zrozumieją protokół V7.”).
Loguj oszczędnie
Podczas gdy logowanie jest konieczne, ma ono negatywny wpływ na wydajność i traci swoją użyteczność, jeśli nie jest utrzymywane w rozsądnym tonie. Narzędzia do logowania zapewniają pięć różnych poziomów logowania:
-
ERROR
: Użyj, gdy stało się coś fatalnego, to znaczy, coś będzie miało konsekwencje widoczne dla użytkownika i nie będzie możliwe do odzyskania bez usunięcia niektórych danych, odinstalowania aplikacji, wymazania partycji danych lub ponownego flashowania całego urządzenia (lub gorzej). Ten poziom jest zawsze rejestrowany. Problemy, które uzasadniają logowanie na poziomieERROR
są dobrymi kandydatami do zgłoszenia do serwera gromadzącego statystyki. -
WARNING
: Używany, gdy stało się coś poważnego i nieoczekiwanego, to znaczy coś, co będzie miało konsekwencje widoczne dla użytkownika, ale prawdopodobnie będzie możliwe do odzyskania bez utraty danych poprzez wykonanie jakiegoś wyraźnego działania, począwszy od czekania lub ponownego uruchomienia aplikacji aż do ponownego pobrania nowej wersji aplikacji lub ponownego uruchomienia urządzenia. Ten poziom jest zawsze rejestrowany. Problemy, które uzasadniają logowanie na poziomieWARNING
mogą być również brane pod uwagę przy raportowaniu do serwera gromadzącego statystyki. -
INFORMATIVE
: Używane do odnotowania, że wydarzyło się coś ciekawego, czyli gdy wykryta zostanie sytuacja, która może mieć szeroki wpływ, choć niekoniecznie jest błędem. Taki stan powinien być rejestrowany tylko przez moduł, który uważa, że jest najbardziej autorytatywny w danej domenie (aby uniknąć podwójnego rejestrowania przez nieautorytatywne komponenty). Ten poziom jest zawsze logowany. -
DEBUG
: Użyj, aby dalej notować, co dzieje się na urządzeniu, które mogą być istotne dla zbadania i debugowania nieoczekiwanych zachowań. Rejestruj tylko to, co jest potrzebne do zebrania wystarczającej ilości informacji o tym, co dzieje się z twoim komponentem. Jeśli logi debugowania dominują w dzienniku, powinieneś użyć logowania verbose.Ten poziom jest logowany nawet na kompilacjach release, i musi być otoczony blokiem
if (LOCAL_LOG)
lubif LOCAL_LOGD)
, gdzieLOCAL_LOG
jest zdefiniowany w twojej klasie lub podkomponencie, tak aby istniała możliwość wyłączenia całego tego logowania. Dlatego nie może być żadnej aktywnej logiki w blokuif (LOCAL_LOG)
. Całe budowanie łańcuchów dla dziennika również musi być umieszczone wewnątrz blokuif (LOCAL_LOG)
. Nie refaktoryzuj wywołania logowania na wywołanie metody, jeśli spowoduje to, że budowanie ciągów znaków będzie miało miejsce poza blokiemif (LOCAL_LOG)
.Jest trochę kodu, który wciąż mówi
if (localLOGV)
. Jest to również uważane za dopuszczalne, chociaż nazwa jest niestandardowa. -
VERBOSE
: Użyj dla wszystkiego innego. Ten poziom jest rejestrowany tylko na kompilacjach debug i powinien być otoczony przez blokif (LOCAL_LOGV)
(lub równoważny), aby mógł być domyślnie skompilowany. Wszelkie budowanie łańcuchów jest usuwane z kompilacji release i musi pojawić się wewnątrz blokuif (LOCAL_LOGV)
.
Wskazówki
- W obrębie danego modułu, innego niż na poziomie
VERBOSE
, błąd powinien być zgłaszany tylko raz, jeśli to możliwe. W ramach pojedynczego łańcucha wywołań funkcji w module, tylko najbardziej wewnętrzna funkcja powinna zwracać błąd, a wywołujący w tym samym module powinni dodawać logowanie tylko wtedy, gdy znacząco pomaga to w wyizolowaniu problemu. - W łańcuchu modułów, innych niż na poziomie
VERBOSE
, gdy moduł niższego poziomu wykryje nieprawidłowe dane pochodzące z modułu wyższego poziomu, moduł niższego poziomu powinien tylko logować tę sytuację doDEBUG
logu, i tylko wtedy, gdy logowanie dostarcza informacji, które nie są w inny sposób dostępne dla wywołującego. W szczególności, nie ma potrzeby rejestrowania sytuacji, w których rzucany jest wyjątek (wyjątek powinien zawierać wszystkie istotne informacje), lub w których jedyna rejestrowana informacja jest zawarta w kodzie błędu. Jest to szczególnie ważne w interakcji pomiędzy frameworkiem a aplikacjami, a warunki spowodowane przez aplikacje firm trzecich, które są poprawnie obsługiwane przez framework, nie powinny wywoływać logowania wyższego niż poziomDEBUG
. Jedyne sytuacje, które powinny wyzwalać logowanie na poziomieINFORMATIVE
lub wyższym, to sytuacje, gdy moduł lub aplikacja wykryje błąd na swoim własnym poziomie lub pochodzący z niższego poziomu. - Gdy stan, który normalnie uzasadniałby pewne logowanie, prawdopodobnie wystąpi wiele razy, dobrym pomysłem może być zaimplementowanie jakiegoś mechanizmu ograniczającego szybkość, aby zapobiec przepełnieniu logów wieloma duplikatami tej samej (lub bardzo podobnej) informacji.
- Utraty łączności sieciowej są uważane za powszechne i w pełni oczekiwane, i nie powinny być bezinteresownie rejestrowane. Utrata łączności sieciowej, która ma konsekwencje w aplikacji, powinna być rejestrowana na poziomie
DEBUG
lubVERBOSE
(w zależności od tego, czy konsekwencje są na tyle poważne i nieoczekiwane, że powinny być rejestrowane w wersji wydanej). - Posiadanie pełnego systemu plików na systemie plików, który jest dostępny dla lub w imieniu aplikacji firm trzecich nie powinno być logowane na poziomie wyższym niż INFORMATYCZNY.
- Nieważne dane pochodzące z jakiegokolwiek niezaufanego źródła (włączając w to jakikolwiek plik na współdzielonym magazynie lub dane przychodzące przez połączenie sieciowe) są uważane za oczekiwane i nie powinny wywoływać żadnego logowania na poziomie wyższym niż
DEBUG
kiedy zostaną wykryte jako nieważne (a nawet wtedy logowanie powinno być tak ograniczone jak to tylko możliwe). - Gdy jest używany na obiektach
String
, operator+
niejawnie tworzy instancjęStringBuilder
z domyślnym rozmiarem bufora (16 znaków) i potencjalnie innymi tymczasowymi obiektamiString
. Tak więc jawne tworzenie obiektówStringBuilder
nie jest droższe niż poleganie na domyślnym operatorze+
(i może być o wiele bardziej wydajne). Należy pamiętać, że kod, który wywołujeLog.v()
jest kompilowany i wykonywany na kompilacjach release, włączając w to budowanie ciągów znaków, nawet jeśli logi nie są czytane. - Każde logowanie, które ma być czytane przez innych ludzi i być dostępne w wydaniach powinno być zwięzłe, ale nie kryptyczne i powinno być zrozumiałe. Dotyczy to wszystkich logów aż do poziomu
DEBUG
. - Kiedy to możliwe, utrzymuj logowanie w jednej linii. Długości linii do 80 lub 100 znaków są akceptowalne. Jeśli to możliwe, unikaj długości dłuższych niż około 130 lub 160 znaków (włączając w to długość znacznika).
- Jeśli logowanie informuje o sukcesie, nigdy nie używaj go na poziomie wyższym niż
VERBOSE
. - Jeśli używasz tymczasowego logowania do zdiagnozowania problemu, który jest trudny do odtworzenia, trzymaj je na poziomie
DEBUG
lubVERBOSE
i obudowuj je blokami if, które pozwalają na wyłączenie go w czasie kompilacji. - Uważaj na wycieki bezpieczeństwa przez dziennik. Unikaj rejestrowania prywatnych informacji. W szczególności, unikaj logowania informacji o chronionej zawartości. Jest to szczególnie ważne podczas pisania kodu frameworka, ponieważ nie jest łatwo wiedzieć z góry, co będzie, a co nie będzie prywatną informacją lub chronioną treścią.
- Nigdy nie używaj
System.out.println()
(lubprintf()
dla natywnego kodu).System.out
iSystem.err
zostaną przekierowane do/dev/null
, więc twoje deklaracje drukowania nie mają widocznych efektów. Jednak wszystkie budowanie ciągów, które dzieje się dla tych połączeń, nadal jest wykonywane. - Złotą zasadą logowania jest to, że twoje logi nie mogą niepotrzebnie wypychać innych logów z bufora, tak samo jak inni nie mogą wypychać twoich.
Zasady stylu testowania
Podążaj za konwencją nazewnictwa metod testowych i używaj podkreślenia, aby oddzielić to, co jest testowane od konkretnego testowanego przypadku. Ten styl sprawia, że łatwiej jest zobaczyć, które przypadki są testowane. For example:
testMethod_specificCase1 testMethod_specificCase2void testIsDistinguishable_protanopia() { ColorMatcher colorMatcher = new ColorMatcher(PROTANOPIA) assertFalse(colorMatcher.isDistinguishable(Color.RED, Color.BLACK)) assertTrue(colorMatcher.isDistinguishable(Color.X, Color.Y))}