blob: d4ee486b052a72cd56e41d879dccd84ebb2aa1d5 [file] [log] [blame] [view]
Andrew Grieve8d9e40f2023-03-15 21:04:421# Chromium Java Style Guide
nyquist9d61f982017-02-10 00:29:082
3_For other languages, please see the [Chromium style
John Palmerbe051302021-05-19 11:48:354guides](https://chromium.googlesource.com/chromium/src/+/main/styleguide/styleguide.md)._
nyquist9d61f982017-02-10 00:29:085
6Chromium follows the [Android Open Source style
7guide](http://source.android.com/source/code-style.html) unless an exception
8is listed below.
9
nyquistaae4c7c2017-02-15 20:41:4210You can propose changes to this style guide by sending an email to
11`[email protected]`. Ideally, the list will arrive at some consensus and you can
12request review for a change to this file. If there's no consensus,
John Palmerbe051302021-05-19 11:48:3513[`//styleguide/java/OWNERS`](https://chromium.googlesource.com/chromium/src/+/main/styleguide/java/OWNERS)
nyquistaae4c7c2017-02-15 20:41:4214get to decide.
15
agrieve0e6bdf22018-08-03 14:25:2416[TOC]
17
Andrew Grieve99e388f2023-11-02 20:46:5118## Java Language Features
Nate Fischer03308e92022-11-07 18:14:5919
Andrew Grieve99e388f2023-11-02 20:46:5120### Type Deduction using "var" {#var}
Nate Fischer03308e92022-11-07 18:14:5921
22A variable declaration can use the `var` keyword in place of the type (similar
23to the `auto` keyword in C++). In line with the [guidance for
24C++](https://google.github.io/styleguide/cppguide.html#Type_deduction), the
25`var` keyword may be used when it aids readability and the type of the value is
26already clear (ex. `var bundle = new Bundle()` is OK, but `var something =
27returnValueIsNotObvious()` may be unclear to readers who are new to this part of
28the code).
29
30The `var` keyword may also be used in try-with-resources when the resource is
31not directly accessed (or when it falls under the previous guidance), such as:
32
33```java
34try (var ignored = StrictModeContext.allowDiskWrites()) {
35 // 'var' is permitted so long as the 'ignored' variable is not used directly
36 // in the code.
37}
38```
39
agrieve398286b2018-08-15 01:44:4540### Exceptions
Andrew Grieve99e388f2023-11-02 20:46:5141
Andrew Grieve318b35322023-01-13 16:03:2342We discourage overly broad catches via `Throwable`, `Exception`, or
43`RuntimeException`, except when dealing with `RemoteException` or similar
44system APIs.
45 * There have been many cases of crashes caused by `IllegalStateException` /
46 `IllegalArgumentException` / `SecurityException` being thrown where only
47 `RemoteException` was being caught. In these cases, use
48 `catch (RemoteException | RuntimeException e)`.
49 * For all broad catch expressions, add a comment to explain why.
agrieve398286b2018-08-15 01:44:4550
Andrew Grieve318b35322023-01-13 16:03:2351Avoid adding messages to exceptions that do not aid in debugging. For example:
agrieve398286b2018-08-15 01:44:4552
agrieve50430de2018-08-15 17:49:1653```java
54try {
Nate Fischerfc38dc812024-04-24 17:07:2655 somethingThatThrowsIOException();
agrieve50430de2018-08-15 17:49:1656} catch (IOException e) {
Nate Fischerfc38dc812024-04-24 17:07:2657 // Bad - message does not tell you more than the stack trace does:
58 throw new RuntimeException("Failed to parse a file.", e);
59 // Good - conveys that this block failed along with the "caused by" exception.
60 throw new RuntimeException(e);
61 // Good - adds useful information.
62 throw new RuntimeException(String.format("Failed to parse %s", fileName), e);
agrieve50430de2018-08-15 17:49:1663}
64```
65
agrieve398286b2018-08-15 01:44:4566### Asserts
Andrew Grieve8d9e40f2023-03-15 21:04:4267
Andrew Grieve087342762023-07-25 01:14:2568The build system:
69 * strips asserts in release builds (via R8),
70 * enables them in debug builds,
71 * and enables them in report-only mode for Canary builds.
agrieve398286b2018-08-15 01:44:4572
73```java
Andrew Grieve087342762023-07-25 01:14:2574// Code for assert expressions & messages is removed when asserts are disabled.
75assert someCallWithoutSideEffects(param) : "Call failed with: " + param;
agrieve398286b2018-08-15 01:44:4576```
77
Andrew Grieve087342762023-07-25 01:14:2578Use your judgement for when to use asserts vs exceptions. Generally speaking,
79use asserts to check program invariants (e.g. parameter constraints) and
80exceptions for unrecoverable error conditions (e.g. OS errors). You should tend
81to use exceptions more in privacy / security-sensitive code.
82
83Do not add checks when the code will crash anyways. E.g.:
84
85```java
86// Don't do this.
87assert(foo != null);
88foo.method(); // This will throw anyways.
89```
90
91For multi-statement asserts, use [`BuildConfig.ENABLE_ASSERTS`] to guard your
92code (similar to `#if DCHECK_IS_ON()` in C++). E.g.:
agrieve398286b2018-08-15 01:44:4593
94```java
Nate Fischer4570ebc32021-06-04 00:44:4595import org.chromium.build.BuildConfig;
96
97...
98
99if (BuildConfig.ENABLE_ASSERTS) {
Nate Fischerfc38dc812024-04-24 17:07:26100 // Any code here will be stripped in release builds by R8.
101 ...
agrieve398286b2018-08-15 01:44:45102}
103```
104
Andrew Grieve087342762023-07-25 01:14:25105[`BuildConfig.ENABLE_ASSERTS`]: https://source.chromium.org/search?q=symbol:BuildConfig%5C.ENABLE_ASSERTS
106
Andrew Grieve99e388f2023-11-02 20:46:51107#### DCHECKS vs Java Asserts {#asserts}
Andrew Grieve087342762023-07-25 01:14:25108
109`DCHECK` and `assert` are similar, but our guidance for them differs:
110 * CHECKs are preferred in C++, whereas asserts are preferred in Java.
111
112This is because as a memory-safe language, logic bugs in Java are much less
113likely to be exploitable.
114
Andrew Grieve99e388f2023-11-02 20:46:51115### toString() {#toString}
Andrew Grieve8d9e40f2023-03-15 21:04:42116
Andrew Grieve99e388f2023-11-02 20:46:51117Use explicit serialization methods (e.g. `toDebugString()` or `getDescription()`)
118instead of `toString()` when dynamic dispatch is not required.
Andrew Grieve8d9e40f2023-03-15 21:04:42119
Andrew Grieve99e388f2023-11-02 20:46:511201. R8 cannot detect when `toString()` is unused, so overrides will not be stripped
121 when unused.
1222. R8 cannot optimize / inline these calls as well as non-overriding methods.
Andrew Grieve8d9e40f2023-03-15 21:04:42123
Andrew Grieve99e388f2023-11-02 20:46:51124### Records & AutoValue {#records}
125
126```java
127// Banned.
128record Rectangle(float length, float width) {}
129```
130
131**Rationale:**
132 * To avoid dead code:
133 * Records and `@AutoValue` generate `equals()`, `hashCode()`, and `toString()`,
134 which `R8` is unable to remove when unused.
135 * When these methods are required, implement them explicitly so that the
136 intention is clear.
137 * Also - supporting `record` requires build system work ([crbug/1493366]).
138
139Example with `equals()` and `hashCode()`:
140
141```java
142public class ValueClass {
143 private final SomeClass mObjMember;
144 private final int mIntMember;
145
146 @Override
147 public boolean equals(Object o) {
148 return o instanceof ValueClass vc
149 && Objects.equals(mObjMember, vc.mObjMember)
150 && mIntMember == vc.mIntMember;
151 }
152
153 @Override
154 public int hashCode() {
155 return Objects.hash(mObjMember, mIntMember);
156 }
157}
158```
159
160[crbug/1493366]: https://crbug.com/1493366
161
162### Enums
163
164Banned. Use [`@IntDef`](#intdefs) instead.
165
166**Rationale:**
167
168Java enums generate a lot of bytecode. Use constants where possible. When a
169custom type hierarchy is required, use explicit classes with inheritance.
Andrew Grieve8d9e40f2023-03-15 21:04:42170
agrieve16c6fe82018-11-27 17:47:49171### Finalizers
Andrew Grieve8d9e40f2023-03-15 21:04:42172
Andrew Grieveec8284602023-10-16 15:53:25173In line with [Google's Java style guide] and [Android's Java style guide],
agrieve16c6fe82018-11-27 17:47:49174never override `Object.finalize()`.
175
176Custom finalizers:
177* are called on a background thread, and at an unpredicatble point in time,
178* swallow all exceptions (asserts won't work),
179* causes additional garbage collector jank.
180
181Classes that need destructor logic should provide an explicit `destroy()`
John Palmerbe051302021-05-19 11:48:35182method. Use [LifetimeAssert](https://chromium.googlesource.com/chromium/src/+/main/base/android/java/src/org/chromium/base/LifetimeAssert.java)
Bo Liu9bb53ca2020-09-22 00:48:10183to ensure in debug builds and tests that `destroy()` is called.
agrieve16c6fe82018-11-27 17:47:49184
Andrew Grieveec8284602023-10-16 15:53:25185[Google's Java style guide]: https://google.github.io/styleguide/javaguide.html#s6.4-finalizers
186[Android's Java style guide]: https://source.android.com/docs/setup/contribute/code-style#dont-use-finalizers
187
Andrew Grieve99e388f2023-11-02 20:46:51188## Java Library APIs
Andrew Grieve8d9e40f2023-03-15 21:04:42189
Andrew Grieve99e388f2023-11-02 20:46:51190Android provides the ability to bundle copies of `java.*` APIs alongside
191application code, known as [Java Library Desugaring]. However, since this
192bundling comes with a performance cost, Chrome does not use it. Treat `java.*`
193APIs the same as you would `android.*` ones and guard them with
194`Build.VERSION.SDK_INT` checks [when necessary]. The one exception is if the
195method is [directly backported by D8] (these are okay to use, since they are
196lightweight). Android Lint will fail if you try to use an API without a
197corresponding `Build.VERSION.SDK_INT` guard or `@RequiresApi` annotation.
198
199[Java Library Desugaring]: https://developer.android.com/studio/write/java8-support-table
200[when necessary]: https://developer.android.com/reference/packages
201[directly backported by D8]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/r8/backported_methods.txt
202
203### Logging
204
205* Use `org.chromium.base.Log` instead of `android.util.Log`.
206 * It provides `%s` support, and ensures log stripping works correctly.
207* Minimize the use of `Log.w()` and `Log.e()`.
208 * Debug and Info log levels are stripped by ProGuard in release builds, and
209 so have no performance impact for shipping builds. However, Warning and
210 Error log levels are not stripped.
211* Function calls in log parameters are *not* stripped by ProGuard.
212
213```java
214Log.d(TAG, "There are %d cats", countCats()); // countCats() not stripped.
215```
216
217### Streams
218
219Most uses of [Java streams] are discouraged. If you can write your code as an
220explicit loop, then do so. The primary reason for this guidance is because the
221lambdas (and method references) needed for streams almost always result in
222larger binary size ([example](https://chromium-review.googlesource.com/c/chromium/src/+/4329952).
223
224The `parallel()` and `parallelStream()` APIs are simpler than their loop
225equivalents, but are are currently banned due to a lack of a compelling use case
226in Chrome. If you find one, please discuss on `[email protected]`.
227
228[Java streams]: https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html
229
230### AndroidX Annotations {#annotations}
231
232* Use them liberally. They are [documented here](https://developer.android.com/studio/write/annotations).
agrieve398286b2018-08-15 01:44:45233 * They generally improve readability.
Andrew Grieve99e388f2023-11-02 20:46:51234 * Many make lint more useful.
Nate Fischer74cd25c2020-12-16 16:17:03235* `javax.annotation.Nullable` vs `androidx.annotation.Nullable`
236 * Always prefer `androidx.annotation.Nullable`.
agrieve398286b2018-08-15 01:44:45237 * It uses `@Retention(SOURCE)` rather than `@Retention(RUNTIME)`.
238
Andrew Grieve99e388f2023-11-02 20:46:51239#### IntDefs {#intdefs}
Carlos Knippschildf2e58c12021-06-03 01:43:37240
Andrew Grieve99e388f2023-11-02 20:46:51241Values can be declared outside or inside the `@interface`. Chromium style is
242to declare inside.
Carlos Knippschildf2e58c12021-06-03 01:43:37243
244```java
245@IntDef({ContactsPickerAction.CANCEL, ContactsPickerAction.CONTACTS_SELECTED,
246 ContactsPickerAction.SELECT_ALL, ContactsPickerAction.UNDO_SELECT_ALL})
247@Retention(RetentionPolicy.SOURCE)
248public @interface ContactsPickerAction {
249 int CANCEL = 0;
250 int CONTACTS_SELECTED = 1;
251 int SELECT_ALL = 2;
252 int UNDO_SELECT_ALL = 3;
253 int NUM_ENTRIES = 4;
254}
255// ...
256void onContactsPickerUserAction(@ContactsPickerAction int action, ...);
257```
258
259Values of `Integer` type are also supported, which allows using a sentinel
260`null` if needed.
261
262[@IntDef annotation]: https://developer.android.com/studio/write/annotations#enum-annotations
263[Android lint]: https://chromium.googlesource.com/chromium/src/+/HEAD/build/android/docs/lint.md
264
Andrew Grieve99e388f2023-11-02 20:46:51265
266## Style / Formatting {#style}
nyquistaae4c7c2017-02-15 20:41:42267
agrieve398286b2018-08-15 01:44:45268### File Headers
John Palmerbe051302021-05-19 11:48:35269* Use the same format as in the [C++ style guide](https://chromium.googlesource.com/chromium/src/+/main/styleguide/c++/c++.md#File-headers).
nyquistaae4c7c2017-02-15 20:41:42270
agrieve398286b2018-08-15 01:44:45271### TODOs
Andrew Grieve8d9e40f2023-03-15 21:04:42272
agrieve398286b2018-08-15 01:44:45273* TODO should follow chromium convention. Examples:
274 * `TODO(username): Some sentence here.`
Alison Gale53c77f62024-04-22 15:16:27275 * `TODO(crbug.com/40192027): Even better to use a bug for context.`
nyquistaae4c7c2017-02-15 20:41:42276
Andrew Grieved99e3c02023-10-25 14:56:48277### Parameter Comments
278
279Use [parameter comments] when they aid in the readability of a function call.
280
281E.g.:
282
283```java
284someMethod(/* enabled= */ true, /* target= */ null, defaultValue);
285```
286
287[parameter comments]: https://errorprone.info/bugpattern/ParameterName
288
289### Default Field Initializers
Andrew Grieve8d9e40f2023-03-15 21:04:42290
nyquist9d61f982017-02-10 00:29:08291* Fields should not be explicitly initialized to default values (see
292 [here](https://groups.google.com/a/chromium.org/d/topic/chromium-dev/ylbLOvLs0bs/discussion)).
nyquistaae4c7c2017-02-15 20:41:42293
Andrew Grieve8d9e40f2023-03-15 21:04:42294### Curly Braces
295
nyquistaae4c7c2017-02-15 20:41:42296Conditional braces should be used, but are optional if the conditional and the
297statement can be on a single line.
298
299Do:
300
301```java
302if (someConditional) return false;
303for (int i = 0; i < 10; ++i) callThing(i);
304```
305
306or
307
308```java
309if (someConditional) {
Nate Fischerfc38dc812024-04-24 17:07:26310 return false;
nyquistaae4c7c2017-02-15 20:41:42311}
312```
313
314Do NOT do:
315
316```java
317if (someConditional)
Nate Fischerfc38dc812024-04-24 17:07:26318 return false;
nyquistaae4c7c2017-02-15 20:41:42319```
320
nyquist2d192c4c2017-03-06 21:36:51321### Import Order
Andrew Grieve8d9e40f2023-03-15 21:04:42322
nyquist2d192c4c2017-03-06 21:36:51323* Static imports go before other imports.
324* Each import group must be separated by an empty line.
325
326This is the order of the import groups:
327
3281. android
Yun Liuf40227d92019-04-04 17:37:463291. androidx
nyquist2d192c4c2017-03-06 21:36:513301. com (except com.google.android.apps.chrome)
3311. dalvik
3321. junit
3331. org
3341. com.google.android.apps.chrome
3351. org.chromium
3361. java
3371. javax
338
Andrew Grieve11c370072023-07-18 13:46:46339## Testing
340
341Googlers, see [go/clank-test-strategy](http://go/clank-test-strategy).
342
343In summary:
344
345* Use real dependencies when feasible and fast. Use Mockito’s `@Mock` most
346 of the time, but write fakes for frequently used dependencies.
347
348* Do not use Robolectric Shadows for Chromium code. Instead, use
349 `setForTesting()` methods so that it is clear that test hooks exist.
350 * When `setForTesting()` methods alter global state, use
351 [`ResettersForTesting.register()`] to ensure that the state is reset
352 between tests. Omit resetting them via `@After` methods.
353
354* Use Robolectric when possible (when tests do not require native). Other
355 times, use on-device tests with one of the following annotations:
356 * [`@Batch(UNIT_TESTS)`] for unit tests
357 * [`@Batch(PER_CLASS)`] for integration tests
358 * [`@DoNotBatch`] for when each test method requires an app restart
359
360[`ResettersForTesting.register()`]: https://source.chromium.org/search?q=symbol:ResettersForTesting.register
361[`@Batch(UNIT_TESTS)`]: https://source.chromium.org/search?q=symbol:Batch.UNIT_TESTS
362[`@Batch(PER_CLASS)`]: https://source.chromium.org/search?q=symbol:Batch.PER_CLASS
363[`@DoNotBatch`]: https://source.chromium.org/search?q=symbol:DoNotBatch
364
365### Test-only Code
Andrew Grieve8d9e40f2023-03-15 21:04:42366
Andrew Grieve0872aad2023-06-26 14:16:31367Functions and fields used only for testing should have `ForTesting` as a
368suffix so that:
Caitlin Fischer210cfab2020-05-07 20:04:30369
Andrew Grieve0872aad2023-06-26 14:16:313701. The `android-binary-size` trybot can [ensure they are removed] in
371 non-test optimized builds (by R8).
3722. [`PRESUMBIT.py`] can ensure no calls are made to such methods outside of
373 tests, and
374
375`ForTesting` methods that are `@CalledByNative` should use
376`@CalledByNativeForTesting` instead.
377
378Symbols that are made public (or package-private) for the sake of tests
379should be annotated with [`@VisibleForTesting`]. Android Lint will check
380that calls from non-test code respect the "otherwise" visibility.
381
Andrew Grievee27a4f712023-07-04 15:16:35382Symbols with a `ForTesting` suffix **should not** be annotated with
Andrew Grieve0872aad2023-06-26 14:16:31383`@VisibleForTesting`. While `otherwise=VisibleForTesting.NONE` exists, it
384is redundant given the "ForTesting" suffix and the associated lint check
Andrew Grievee27a4f712023-07-04 15:16:35385is redundant given our trybot check. You should, however, use it for
386test-only constructors.
Andrew Grieve0872aad2023-06-26 14:16:31387
388[ensure they are removed]: /docs/speed/binary_size/android_binary_size_trybot.md#Added-Symbols-named-ForTest
389[`PRESUMBIT.py`]: https://chromium.googlesource.com/chromium/src/+/main/PRESUBMIT.py
390[`@VisibleForTesting`]: https://developer.android.com/reference/androidx/annotation/VisibleForTesting
Sam Maier7452a0d2022-07-20 18:24:35391
nyquist9d61f982017-02-10 00:29:08392## Location
Andrew Grieve8d9e40f2023-03-15 21:04:42393
nyquist9d61f982017-02-10 00:29:08394"Top level directories" are defined as directories with a GN file, such as
John Palmerbe051302021-05-19 11:48:35395[//base](https://chromium.googlesource.com/chromium/src/+/main/base/)
nyquist9d61f982017-02-10 00:29:08396and
John Palmerbe051302021-05-19 11:48:35397[//content](https://chromium.googlesource.com/chromium/src/+/main/content/),
nyquist9d61f982017-02-10 00:29:08398Chromium Java should live in a directory named
399`<top level directory>/android/java`, with a package name
400`org.chromium.<top level directory>`. Each top level directory's Java should
401build into a distinct JAR that honors the abstraction specified in a native
John Palmerbe051302021-05-19 11:48:35402[checkdeps](https://chromium.googlesource.com/chromium/buildtools/+/main/checkdeps/checkdeps.py)
nyquist9d61f982017-02-10 00:29:08403(e.g. `org.chromium.base` does not import `org.chromium.content`). The full
404path of any java file should contain the complete package name.
405
406For example, top level directory `//base` might contain a file named
407`base/android/java/org/chromium/base/Class.java`. This would get compiled into a
408`chromium_base.jar` (final JAR name TBD).
409
410`org.chromium.chrome.browser.foo.Class` would live in
411`chrome/android/java/org/chromium/chrome/browser/foo/Class.java`.
412
413New `<top level directory>/android` directories should have an `OWNERS` file
414much like
John Palmerbe051302021-05-19 11:48:35415[//base/android/OWNERS](https://chromium.googlesource.com/chromium/src/+/main/base/android/OWNERS).
nyquist9d61f982017-02-10 00:29:08416
Andrew Grieve0872aad2023-06-26 14:16:31417## Tools
418
Andrew Grieveec8284602023-10-16 15:53:25419`google-java-format` is used to auto-format Java files. Formatting of its code
420should be accepted in code reviews.
Andrew Grieve0872aad2023-06-26 14:16:31421
422You can run `git cl format` to apply the automatic formatting.
423
Andrew Grieveec8284602023-10-16 15:53:25424Chromium also makes use of several [static analysis] tools.
Andrew Grieve0872aad2023-06-26 14:16:31425
Andrew Grieveec8284602023-10-16 15:53:25426[static analysis]: /build/android/docs/static_analysis.md
Andrew Grieve0872aad2023-06-26 14:16:31427
nyquistaae4c7c2017-02-15 20:41:42428## Miscellany
Andrew Grieve8d9e40f2023-03-15 21:04:42429
nyquistaae4c7c2017-02-15 20:41:42430* Use UTF-8 file encodings and LF line endings.