For other languages, please see the Chromium style guides.
Chromium follows the Android Open Source style guide unless an exception is listed below.
You can propose changes to this style guide by sending an email to [email protected]
. Ideally, the list will arrive at some consensus and you can request review for a change to this file. If there's no consensus, //styleguide/java/OWNERS
get to decide.
Desugar is used to rewrite some Java 7 & 8 language constructs in a way that is compatible with Java 6 (and thus all Android versions). Use of these features is encouraged, but there are some gotchas:
Exception
/ Throwable
/ RuntimeException
.It is OK to do:
try { somethingThatThrowsIOException(filePath); somethingThatThrowsParseException(filePath); } catch (IOException | ParseException e) { Log.w(TAG, "Failed to read: %s", filePath, e); }
For example:
try { somethingThatThrowsIOException(); } catch (IOException e) { // Bad - message does not tell you more than the stack trace does: throw new RuntimeException("Failed to parse a file.", e); // Good - conveys that this block failed along with the "caused by" exception. throw new RuntimeException(e); // Good - adds useful information. throw new RuntimeException(String.format("Failed to parse %s", fileName), e); }
org.chromium.base.Log
instead of android.util.Log
.%s
support, and ensures log stripping works correctly.Log.w()
and Log.e()
.Log.d(TAG, "There are %d cats", countCats()); // countCats() not stripped.
The Chromium build system strips asserts in release builds (via ProGuard) and enables them in debug builds (or when dcheck_always_on=true
) (via a build step). You should use asserts in the same scenarios where C++ DCHECK()s make sense. For multi-statement asserts, use org.chromium.build.BuildConfig.ENABLE_ASSERTS
to guard your code (similar to #if DCHECK_IS_ON()
in C++).
Example assert:
assert someCallWithoutSideEffects() : "assert description";
Example use of BuildConfig.ENABLE_ASSERTS
:
import org.chromium.build.BuildConfig; ... if (BuildConfig.ENABLE_ASSERTS) { // Any code here will be stripped in Release by ProGuard. ... }
In line with Google's Java style guide, never override Object.finalize()
.
Custom finalizers:
Classes that need destructor logic should provide an explicit destroy()
method. Use LifetimeAssert to ensure in debug builds and tests that destroy()
is called.
javax.annotation.Nullable
vs androidx.annotation.Nullable
androidx.annotation.Nullable
.@Retention(SOURCE)
rather than @Retention(RUNTIME)
.Java enums generate far more bytecode than integer constants. When integers are sufficient, prefer using an @IntDef annotation, which will have usage checked by Android lint.
Values can be declared outside or inside the @interface
. We recommend the latter, with constants nested within it as follows:
@IntDef({ContactsPickerAction.CANCEL, ContactsPickerAction.CONTACTS_SELECTED, ContactsPickerAction.SELECT_ALL, ContactsPickerAction.UNDO_SELECT_ALL}) @Retention(RetentionPolicy.SOURCE) public @interface ContactsPickerAction { int CANCEL = 0; int CONTACTS_SELECTED = 1; int SELECT_ALL = 2; int UNDO_SELECT_ALL = 3; int NUM_ENTRIES = 4; } // ... void onContactsPickerUserAction(@ContactsPickerAction int action, ...);
Values of Integer
type are also supported, which allows using a sentinel null
if needed.
A checkout should give you clang-format to automatically format Java code. It is suggested that Clang's formatting of code should be accepted in code reviews.
You can run git cl format
to apply the automatic formatting.
For automatically using the correct style, follow the guide to set up your favorite IDE:
Checkstyle is automatically run by the build bots, and to ensure you do not have any surprises, you can also set up checkstyle locally using this guide.
Lint is run as part of the build. For more information, see here.
TODO(username): Some sentence here.
TODO(crbug.com/123456): Even better to use a bug for context.
Conditional braces should be used, but are optional if the conditional and the statement can be on a single line.
Do:
if (someConditional) return false; for (int i = 0; i < 10; ++i) callThing(i);
or
if (someConditional) { return false; }
Do NOT do:
if (someConditional) return false;
This is the order of the import groups:
Functions used only for testing should be restricted to test-only usages with the testing suffixes supported PRESUMBIT.py. ForTesting
is the conventional suffix although similar patterns, such as ForTest
, are also accepted. These suffixes are checked at presubmit time to ensure the functions are called only by test files.
It's generally bad practice to directly call test-only methods from non-test-only code. However, occasionally it has to be done, and if so, you should guard the check with an if (BuildConfig.IS_FOR_TEST)
so that our Java optimizer can still remove the call in non-test builds.
“Top level directories” are defined as directories with a GN file, such as //base and //content, Chromium Java should live in a directory named <top level directory>/android/java
, with a package name org.chromium.<top level directory>
. Each top level directory's Java should build into a distinct JAR that honors the abstraction specified in a native checkdeps (e.g. org.chromium.base
does not import org.chromium.content
). The full path of any java file should contain the complete package name.
For example, top level directory //base
might contain a file named base/android/java/org/chromium/base/Class.java
. This would get compiled into a chromium_base.jar
(final JAR name TBD).
org.chromium.chrome.browser.foo.Class
would live in chrome/android/java/org/chromium/chrome/browser/foo/Class.java
.
New <top level directory>/android
directories should have an OWNERS
file much like //base/android/OWNERS.