Gaya kode Java AOSP untuk kontributor

Gaya kode di halaman ini adalah aturan ketat untuk menyumbangkan kode Java ke Proyek Sumber Terbuka Android (AOSP). Kontribusi pada platform Android yang tidak mematuhi aturan ini umumnya tidak diterima . Kami menyadari bahwa tidak semua kode yang ada mengikuti aturan ini, namun kami berharap semua kode baru mematuhinya. Lihat Pengodean sehubungan dengan contoh terminologi yang harus digunakan dan dihindari demi ekosistem yang lebih inklusif.

Bersikaplah konsisten

Salah satu aturan paling sederhana adalah JADILAH KONSISTEN. Jika Anda mengedit kode, luangkan beberapa menit untuk melihat kode di sekitarnya dan menentukan gayanya. Jika kode tersebut menggunakan spasi di sekitar klausa if , Anda juga harus melakukannya. Jika komentar kode memiliki kotak-kotak kecil bintang di sekelilingnya, buatlah komentar Anda juga memiliki kotak-kotak kecil bintang di sekelilingnya.

Tujuan dari memiliki pedoman gaya adalah untuk memiliki kosa kata pengkodean yang umum, sehingga pembaca dapat berkonsentrasi pada apa yang Anda katakan, bukan pada cara Anda mengatakannya. Kami menyajikan aturan gaya global di sini agar Anda mengetahui kosakatanya, tetapi gaya lokal juga penting. Jika kode yang Anda tambahkan ke file terlihat sangat berbeda dari kode yang ada di sekitarnya, hal ini akan membuat pembaca kehilangan ritme saat membacanya. Cobalah untuk menghindari ini.

Aturan bahasa Jawa

Android mengikuti konvensi pengkodean Java standar dengan aturan tambahan yang dijelaskan di bawah.

Jangan abaikan pengecualian

Anda mungkin tergoda untuk menulis kode yang mengabaikan pengecualian, seperti:

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

Jangan lakukan ini. Meskipun Anda mungkin berpikir kode Anda tidak akan pernah mengalami kondisi kesalahan ini atau tidak penting untuk menanganinya, mengabaikan jenis pengecualian ini akan menciptakan ranjau dalam kode Anda untuk dipicu oleh orang lain suatu hari nanti. Anda harus menangani setiap pengecualian dalam kode Anda dengan cara yang berprinsip; penanganan spesifiknya berbeda-beda tergantung kasusnya.

" Setiap kali seseorang memiliki klausul tangkapan yang kosong, mereka pasti merasakan perasaan yang menyeramkan. Pasti ada saat-saat di mana hal itu sebenarnya adalah hal yang benar untuk dilakukan, tetapi setidaknya Anda harus memikirkannya. Di Jawa, Anda tidak bisa lepas dari perasaan menyeramkan tersebut. "-James Gosling

Alternatif yang dapat diterima (dalam urutan preferensi) adalah:

  • Lemparkan pengecualian ke pemanggil metode Anda.
      void setServerPort(String value) throws NumberFormatException {
          serverPort = Integer.parseInt(value);
      }
    
  • Berikan pengecualian baru yang sesuai dengan tingkat abstraksi Anda.
      void setServerPort(String value) throws ConfigurationException {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new ConfigurationException("Port " + value + " is not valid.");
        }
      }
    
  • Tangani kesalahan dengan baik dan gantikan nilai yang sesuai di blok 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
        }
      }
    
  • Tangkap pengecualian dan lemparkan instance baru RuntimeException . Ini berbahaya, jadi lakukan hanya jika Anda yakin jika kesalahan ini terjadi, tindakan yang tepat adalah 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);
        }
      }
    
  • Sebagai upaya terakhir, jika Anda yakin bahwa mengabaikan pengecualian adalah tindakan yang tepat maka Anda dapat mengabaikannya, namun Anda juga harus memberi komentar alasannya dengan alasan yang masuk akal.
    /** 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.
        }
    }
    

Jangan menangkap pengecualian umum

Anda mungkin tergoda untuk bermalas-malasan saat menangkap pengecualian dan melakukan hal seperti ini:

  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!
  }

Jangan lakukan ini. Di hampir semua kasus, tidak tepat untuk menangkap Exception atau Throwable generik (sebaiknya tidak Throwable karena menyertakan pengecualian Error ). Ini berbahaya karena ini berarti pengecualian yang tidak pernah Anda duga (termasuk pengecualian waktu proses seperti ClassCastException ) terjebak dalam penanganan kesalahan tingkat aplikasi. Ini mengaburkan properti penanganan kegagalan kode Anda, artinya jika seseorang menambahkan tipe pengecualian baru pada kode yang Anda panggil, kompiler tidak akan menunjukkan bahwa Anda perlu menangani kesalahan secara berbeda. Dalam kebanyakan kasus, Anda tidak boleh menangani berbagai jenis pengecualian dengan cara yang sama.

Pengecualian yang jarang terjadi pada aturan ini adalah kode pengujian dan kode tingkat atas tempat Anda ingin menangkap semua jenis kesalahan (untuk mencegahnya muncul di UI, atau untuk menjaga agar tugas batch tetap berjalan). Dalam kasus ini, Anda dapat menangkap Exception generik (atau Throwable ) dan menangani kesalahan dengan tepat. Namun, pikirkan baik-baik sebelum melakukan ini, dan berikan komentar yang menjelaskan mengapa ini aman dalam konteks ini.

Alternatif untuk menangkap pengecualian umum:

  • Tangkap setiap pengecualian secara terpisah sebagai bagian dari blok multi-tangkapan, misalnya:
    try {
        ...
    } catch (ClassNotFoundException | NoSuchMethodException e) {
        ...
    }
  • Perbaiki kode Anda untuk mendapatkan penanganan kesalahan yang lebih terperinci, dengan beberapa blok percobaan. Pisahkan IO dari penguraian, dan tangani kesalahan secara terpisah dalam setiap kasus.
  • Lemparkan kembali pengecualian tersebut. Seringkali Anda tidak perlu menangkap pengecualian pada level ini, biarkan saja metode tersebut membuangnya.

Ingatlah bahwa pengecualian adalah teman Anda! Ketika kompiler mengeluh bahwa Anda tidak menemukan pengecualian, jangan cemberut. Senyum! Kompiler mempermudah Anda menemukan masalah runtime dalam kode Anda.

Jangan gunakan finalizer

Finalizer adalah cara untuk mengeksekusi sebagian kode ketika suatu objek dikumpulkan dari sampah. Meskipun finalizer berguna untuk pembersihan (khususnya sumber daya eksternal), tidak ada jaminan kapan finalizer akan dipanggil (atau bahkan akan dipanggil sama sekali).

Android tidak menggunakan finalizer. Dalam kebanyakan kasus, Anda dapat menggunakan penanganan pengecualian yang baik. Jika Anda benar-benar membutuhkan finalizer, tentukan metode close() (atau sejenisnya) dan dokumentasikan kapan tepatnya metode tersebut perlu dipanggil (lihat InputStream sebagai contoh). Dalam hal ini, pantas namun tidak diperlukan untuk mencetak pesan log singkat dari finalizer, asalkan tidak diperkirakan akan membanjiri log.

Impor yang sepenuhnya memenuhi syarat

Saat Anda ingin menggunakan class Bar dari paket foo , ada dua cara yang mungkin untuk mengimpornya:

  • import foo.*;

    Berpotensi mengurangi jumlah pernyataan impor.

  • import foo.Bar;

    Memperjelas kelas apa yang digunakan dan kodenya lebih mudah dibaca oleh pengelola.

Gunakan import foo.Bar; untuk mengimpor semua kode Android. Pengecualian eksplisit dibuat untuk perpustakaan standar Java ( java.util.* , java.io.* , dll.) dan kode pengujian unit ( junit.framework.* ).

Aturan perpustakaan Java

Ada konvensi untuk menggunakan pustaka dan alat Java Android. Dalam beberapa kasus, konvensi telah berubah secara signifikan dan kode lama mungkin menggunakan pola atau pustaka yang tidak digunakan lagi. Saat bekerja dengan kode seperti itu, tidak masalah untuk melanjutkan gaya yang sudah ada. Namun saat membuat komponen baru, jangan pernah menggunakan perpustakaan yang sudah tidak digunakan lagi.

Aturan gaya Java

Gunakan komentar standar Javadoc

Setiap file harus memiliki pernyataan hak cipta di bagian atas, diikuti oleh pernyataan paket dan impor (setiap blok dipisahkan oleh baris kosong), dan terakhir deklarasi kelas atau antarmuka. Di komentar Javadoc, jelaskan apa yang dilakukan kelas atau antarmuka.

/*
 * Copyright 2024 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 {
    ...
}

Setiap kelas dan metode publik nontrivial yang Anda tulis harus berisi komentar Javadoc dengan setidaknya satu kalimat yang menjelaskan apa yang dilakukan kelas atau metode tersebut. Kalimat ini harus dimulai dengan kata kerja deskriptif orang ketiga.

Contoh

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

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

atau

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

Anda tidak perlu menulis Javadoc untuk metode get dan set yang sepele seperti setFoo() jika yang dikatakan Javadoc Anda hanyalah "set Foo". Jika metode tersebut melakukan sesuatu yang lebih kompleks (seperti menerapkan batasan atau memiliki efek samping yang penting), maka Anda harus mendokumentasikannya. Jika tidak jelas apa arti properti "Foo", Anda harus mendokumentasikannya.

Setiap metode yang Anda tulis, publik atau lainnya, akan mendapat manfaat dari Javadoc. Metode publik adalah bagian dari API dan oleh karena itu memerlukan Javadoc. Android tidak menerapkan gaya khusus untuk menulis komentar Javadoc, namun Anda harus mengikuti petunjuk di Cara Menulis Komentar Dokumen untuk Alat Javadoc .

Tulis metode singkat

Jika memungkinkan, pertahankan metode yang kecil dan fokus. Kami menyadari bahwa metode yang panjang kadang-kadang tepat, jadi tidak ada batasan pasti mengenai panjang metode. Jika suatu metode melebihi 40 baris atau lebih, pikirkan apakah metode tersebut dapat dipecah tanpa merusak struktur program.

Tentukan bidang di tempat standar

Tentukan bidang di bagian atas file atau tepat sebelum metode yang menggunakannya.

Batasi cakupan variabel

Minimalkan cakupan variabel lokal. Hal ini meningkatkan keterbacaan dan pemeliharaan kode Anda serta mengurangi kemungkinan kesalahan. Deklarasikan setiap variabel di blok terdalam yang melingkupi semua kegunaan variabel tersebut.

Deklarasikan variabel lokal pada titik di mana variabel tersebut pertama kali digunakan. Hampir setiap deklarasi variabel lokal harus berisi inisialisasi. Jika Anda belum memiliki informasi yang cukup untuk menginisialisasi variabel dengan benar, tunda deklarasi sampai Anda memilikinya.

Pengecualiannya adalah pernyataan coba-tangkap. Jika suatu variabel diinisialisasi dengan nilai kembalian dari metode yang menampilkan pengecualian yang dicentang, variabel tersebut harus diinisialisasi di dalam blok try. Jika nilai harus digunakan di luar blok try, maka nilai tersebut harus dideklarasikan sebelum blok try, dimana nilai tersebut belum dapat diinisialisasi dengan baik:

// 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));

Namun, Anda bahkan dapat menghindari kasus ini dengan merangkum blok try-catch dalam sebuah metode:

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));

Deklarasikan variabel loop dalam pernyataan for itu sendiri kecuali ada alasan kuat untuk melakukan sebaliknya:

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

Dan

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

Pernyataan impor pesanan

Urutan pernyataan impor adalah:

  1. Impor Android
  2. Impor dari pihak ketiga ( com , junit , net , org )
  3. java dan javax

Agar sama persis dengan pengaturan IDE, impornya harus:

  • Sesuai abjad dalam setiap pengelompokan, dengan huruf kapital sebelum huruf kecil (misalnya, Z sebelum a)
  • Dipisahkan oleh baris kosong antara setiap pengelompokan utama ( android , com , junit , net , org , java , javax )

Awalnya, tidak ada persyaratan gaya pada pengurutan, artinya IDE selalu mengubah pengurutan atau pengembang IDE harus menonaktifkan fitur manajemen impor otomatis dan mengelola impor secara manual. Hal ini dianggap buruk. Ketika gaya Java ditanya, gaya yang disukai sangat bervariasi dan Android harus "memilih urutan dan konsisten". Jadi kami memilih gaya, memperbarui panduan gaya, dan membuat IDE mematuhinya. Kami berharap saat pengguna IDE mengerjakan kode tersebut, impor di semua paket akan cocok dengan pola ini tanpa upaya rekayasa tambahan.

Kami memilih gaya ini sedemikian rupa sehingga:

  • Impor yang pertama kali ingin dilihat orang cenderung berada di atas ( android ).
  • Impor yang paling ingin dilihat orang cenderung berada di bawah ( java ).
  • Manusia dapat dengan mudah mengikuti gaya tersebut.
  • IDE dapat mengikuti gayanya.

Tempatkan impor statis di atas semua impor lainnya yang diurutkan dengan cara yang sama seperti impor biasa.

Gunakan spasi untuk lekukan

Kami menggunakan empat (4) indentasi spasi untuk blok dan tidak pernah menggunakan tab. Jika ragu, konsistenlah dengan kode di sekitarnya.

Kami menggunakan delapan (8) indentasi spasi untuk pembungkusan baris, termasuk pemanggilan fungsi dan penetapan.

Direkomendasikan

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

Tidak direkomendasikan

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

Ikuti konvensi penamaan bidang

  • Nama bidang non-publik dan non-statis dimulai dengan m .
  • Nama bidang statis dimulai dengan s .
  • Bidang lainnya dimulai dengan huruf kecil.
  • Bidang akhir statis (konstanta, sangat tidak dapat diubah) adalah ALL_CAPS_WITH_UNDERSCORES .

Misalnya:

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;
}

Gunakan gaya kurung kurawal standar

Letakkan kurung kurawal pada baris yang sama dengan kode sebelumnya, bukan pada barisnya sendiri:

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

Kita memerlukan kurung kurawal di sekitar pernyataan untuk sebuah kondisi. Pengecualian: Jika seluruh kondisi (kondisi dan isi) muat dalam satu baris, Anda boleh (tetapi tidak wajib) meletakkan semuanya dalam satu baris. Misalnya, hal ini dapat diterima:

if (condition) {
    body();
}

dan ini dapat diterima:

if (condition) body();

tapi ini tidak bisa diterima:

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

Batasi panjang garis

Setiap baris teks dalam kode Anda panjangnya maksimal 100 karakter. Meskipun banyak diskusi telah membahas aturan ini, keputusannya tetap bahwa 100 karakter adalah jumlah maksimum dengan pengecualian berikut :

  • Jika baris komentar berisi contoh perintah atau URL literal yang panjangnya lebih dari 100 karakter, baris tersebut mungkin lebih panjang dari 100 karakter untuk kemudahan potong dan tempel.
  • Garis yang diimpor bisa melampaui batas karena manusia jarang melihatnya (ini juga menyederhanakan penulisan alat).

Gunakan anotasi Java standar

Anotasi harus mendahului pengubah lain untuk elemen bahasa yang sama. Anotasi penanda sederhana (misalnya, @Override ) dapat dicantumkan pada baris yang sama dengan elemen bahasa. Jika ada beberapa anotasi, atau anotasi berparameter, cantumkan anotasi tersebut satu per baris dalam urutan abjad.

Praktik standar Android untuk tiga anotasi standar di Java adalah:

  • Gunakan anotasi @Deprecated setiap kali penggunaan elemen beranotasi tidak disarankan. Jika Anda menggunakan anotasi @Deprecated , Anda juga harus memiliki tag Javadoc @deprecated dan tag tersebut harus memberi nama implementasi alternatif. Selain itu, ingatlah bahwa metode @Deprecated masih berfungsi . Jika Anda melihat kode lama yang memiliki tag Javadoc @deprecated , tambahkan anotasi @Deprecated .
  • Gunakan anotasi @Override setiap kali metode mengambil alih deklarasi atau implementasi dari superkelas. Misalnya, jika Anda menggunakan tag Javadoc @inheritdocs , dan berasal dari suatu kelas (bukan antarmuka), Anda juga harus memberi anotasi bahwa metode tersebut menggantikan metode kelas induk.
  • Gunakan anotasi @SuppressWarnings hanya dalam keadaan di mana peringatan tidak dapat dihilangkan. Jika peringatan lolos uji "tidak mungkin dihilangkan" ini, anotasi @SuppressWarnings harus digunakan, untuk memastikan bahwa semua peringatan mencerminkan masalah sebenarnya dalam kode.

    Jika anotasi @SuppressWarnings diperlukan, anotasi tersebut harus diawali dengan komentar TODO yang menjelaskan kondisi "tidak mungkin dihilangkan". Ini biasanya mengidentifikasi kelas yang melanggar yang memiliki antarmuka yang canggung. Misalnya:

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

    Jika anotasi @SuppressWarnings diperlukan, lakukan pemfaktoran ulang kode untuk mengisolasi elemen perangkat lunak yang menerapkan anotasi tersebut.

Perlakukan akronim sebagai kata-kata

Perlakukan akronim dan singkatan sebagai kata-kata dalam penamaan variabel, metode, dan kelas agar nama lebih mudah dibaca:

Bagus Buruk
Permintaan XmlHttp Permintaan XMLHTTP
dapatkanCustomerId dapatkan ID Pelanggan
kelas HTML kelas HTML
URL string URL tali
identitas panjang tanda pengenal yang panjang

Karena basis kode JDK dan Android tidak konsisten dalam hal akronim, hampir tidak mungkin untuk konsisten dengan kode di sekitarnya. Oleh karena itu, selalu perlakukan akronim sebagai kata-kata.

Gunakan komentar TODO

Gunakan komentar TODO untuk kode yang bersifat sementara, solusi jangka pendek, atau cukup baik tetapi tidak sempurna. Komentar ini harus menyertakan string TODO dalam huruf kapital semua, diikuti dengan titik dua:

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

Dan

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

Jika TODO Anda berbentuk "Di masa mendatang, lakukan sesuatu" pastikan Anda menyertakan tanggal tertentu ("Perbaiki sebelum November 2005") atau peristiwa tertentu ("Hapus kode ini setelah semua pencampur produksi memahami protokol V7." ).

Catat dengan hemat

Meskipun logging diperlukan, hal ini berdampak negatif pada kinerja dan kehilangan kegunaannya jika tidak dijaga dengan cukup singkat. Fasilitas logging menyediakan lima tingkat logging yang berbeda:

  • ERROR : Gunakan ketika sesuatu yang fatal telah terjadi, yaitu, sesuatu akan mempunyai konsekuensi yang terlihat oleh pengguna dan tidak dapat dipulihkan tanpa menghapus beberapa data, mencopot pemasangan aplikasi, menghapus partisi data, atau mem-flash ulang seluruh perangkat (atau lebih buruk lagi). Level ini selalu dicatat. Permasalahan yang membenarkan adanya beberapa pencatatan pada tingkat ERROR merupakan kandidat yang baik untuk dilaporkan ke server pengumpul statistik.
  • WARNING : Gunakan ketika sesuatu yang serius dan tidak terduga terjadi, yaitu sesuatu yang memiliki konsekuensi yang terlihat oleh pengguna namun kemungkinan dapat dipulihkan tanpa kehilangan data dengan melakukan beberapa tindakan eksplisit, mulai dari menunggu atau memulai ulang aplikasi hingga mengunduh ulang versi baru aplikasi atau me-reboot perangkat. Level ini selalu dicatat. Masalah yang membenarkan pencatatan pada tingkat WARNING juga dapat dipertimbangkan untuk dilaporkan ke server pengumpul statistik.
  • INFORMATIVE : Digunakan untuk mencatat bahwa sesuatu yang menarik telah terjadi, yaitu ketika terdeteksi adanya situasi yang mungkin berdampak luas, namun belum tentu merupakan kesalahan. Kondisi seperti ini hanya boleh dicatat oleh modul yang meyakini bahwa modul tersebut adalah yang paling otoritatif di domain tersebut (untuk menghindari duplikasi logging oleh komponen yang tidak otoritatif). Level ini selalu dicatat.
  • DEBUG : Gunakan untuk mencatat lebih lanjut apa yang terjadi pada perangkat yang mungkin relevan untuk menyelidiki dan men-debug perilaku yang tidak terduga. Catat hanya apa yang diperlukan untuk mengumpulkan informasi yang cukup tentang apa yang terjadi dengan komponen Anda. Jika log debug Anda mendominasi log, Anda harus menggunakan logging verbose.

    Level ini dicatat bahkan pada versi rilis, dan harus dikelilingi oleh blok if (LOCAL_LOG) atau if LOCAL_LOGD) , di mana LOCAL_LOG[D] didefinisikan di kelas atau subkomponen Anda, sehingga ada kemungkinan untuk menonaktifkan semua logging tersebut . Oleh karena itu, tidak boleh ada logika aktif di blok if (LOCAL_LOG) . Semua pembuatan string untuk log juga perlu ditempatkan di dalam blok if (LOCAL_LOG) . Jangan memfaktorkan ulang pemanggilan logging menjadi pemanggilan metode jika hal itu akan menyebabkan pembuatan string terjadi di luar blok if (LOCAL_LOG) .

    Ada beberapa kode yang masih bertuliskan if (localLOGV) . Hal ini dianggap dapat diterima juga, meskipun namanya tidak standar.

  • VERBOSE : Gunakan untuk yang lainnya. Level ini hanya dicatat pada build debug dan harus dikelilingi oleh blok if (LOCAL_LOGV) (atau yang setara) sehingga dapat dikompilasi secara default. Pembuatan string apa pun dikeluarkan dari versi rilis dan harus muncul di dalam blok if (LOCAL_LOGV) .

Catatan

  • Dalam modul tertentu, selain pada tingkat VERBOSE , kesalahan hanya boleh dilaporkan satu kali jika memungkinkan. Dalam satu rangkaian pemanggilan fungsi dalam sebuah modul, hanya fungsi terdalam yang harus mengembalikan kesalahan, dan pemanggil dalam modul yang sama hanya boleh menambahkan beberapa logging jika hal tersebut secara signifikan membantu mengisolasi masalah.
  • Dalam rantai modul, selain pada tingkat VERBOSE , ketika modul tingkat yang lebih rendah mendeteksi data yang tidak valid yang berasal dari modul tingkat yang lebih tinggi, modul tingkat yang lebih rendah hanya akan mencatat situasi ini ke log DEBUG , dan hanya jika logging menyediakan informasi yang tidak tersedia bagi penelepon. Secara khusus, tidak perlu mencatat situasi ketika pengecualian dilemparkan (pengecualian harus berisi semua informasi yang relevan), atau ketika satu-satunya informasi yang dicatat terkandung dalam kode kesalahan. Hal ini sangat penting dalam interaksi antara kerangka kerja dan aplikasi, dan kondisi yang disebabkan oleh aplikasi pihak ketiga yang ditangani dengan benar oleh kerangka kerja tidak boleh memicu logging lebih tinggi dari tingkat DEBUG . Satu-satunya situasi yang harus memicu logging pada tingkat INFORMATIVE atau lebih tinggi adalah ketika modul atau aplikasi mendeteksi kesalahan pada tingkatnya sendiri atau berasal dari tingkat yang lebih rendah.
  • Ketika suatu kondisi yang biasanya membenarkan beberapa logging mungkin terjadi berkali-kali, ada baiknya menerapkan beberapa mekanisme pembatasan laju untuk mencegah meluapnya log dengan banyak salinan duplikat dari informasi yang sama (atau sangat mirip).
  • Hilangnya konektivitas jaringan dianggap umum dan merupakan hal yang wajar terjadi, dan tidak boleh dicatat secara sembarangan. Hilangnya konektivitas jaringan yang memiliki konsekuensi dalam suatu aplikasi harus dicatat di tingkat DEBUG atau VERBOSE (bergantung pada apakah konsekuensinya cukup serius dan tidak terduga untuk dicatat dalam versi rilis).
  • Memiliki sistem file lengkap pada sistem file yang dapat diakses oleh atau atas nama aplikasi pihak ketiga tidak boleh dicatat pada tingkat yang lebih tinggi dari INFORMATIVE.
  • Data tidak valid yang berasal dari sumber tidak tepercaya (termasuk file apa pun di penyimpanan bersama, atau data yang datang melalui koneksi jaringan) dianggap diharapkan dan tidak boleh memicu pencatatan log apa pun pada tingkat yang lebih tinggi dari DEBUG ketika terdeteksi tidak valid (dan bahkan pencatatan log tersebut harus dibatasi semaksimal mungkin).
  • Saat digunakan pada objek String , operator + secara implisit membuat instance StringBuilder dengan ukuran buffer default (16 karakter) dan kemungkinan objek String sementara lainnya. Jadi secara eksplisit membuat objek StringBuilder tidak lebih mahal daripada mengandalkan operator + default (dan bisa jauh lebih efisien). Ingatlah bahwa kode yang memanggil Log.v() dikompilasi dan dieksekusi pada build rilis, termasuk membuat string, meskipun log tidak dibaca.
  • Pencatatan log apa pun yang dimaksudkan untuk dibaca oleh orang lain dan tersedia dalam versi rilis harus singkat, tidak samar-samar, dan harus dapat dimengerti. Ini mencakup semua pencatatan ke tingkat DEBUG .
  • Jika memungkinkan, tetaplah login dalam satu baris. Panjang baris hingga 80 atau 100 karakter dapat diterima. Hindari panjang yang melebihi 130 atau 160 karakter (termasuk panjang tag) jika memungkinkan.
  • Jika laporan logging berhasil, jangan pernah menggunakannya pada tingkat yang lebih tinggi dari VERBOSE .
  • Jika Anda menggunakan pencatatan sementara untuk mendiagnosis masalah yang sulit untuk direproduksi, pertahankan pada tingkat DEBUG atau VERBOSE dan sertakan dengan blok if yang memungkinkan untuk menonaktifkannya pada waktu kompilasi.
  • Hati-hati dengan kebocoran keamanan melalui log. Hindari mencatat informasi pribadi. Secara khusus, hindari mencatat informasi tentang konten yang dilindungi. Hal ini sangat penting ketika menulis kode kerangka kerja karena tidak mudah untuk mengetahui terlebih dahulu apa yang akan dan tidak akan menjadi informasi pribadi atau konten yang dilindungi.
  • Jangan pernah menggunakan System.out.println() (atau printf() untuk kode asli). System.out dan System.err dialihkan ke /dev/null , sehingga pernyataan print Anda tidak memiliki efek yang terlihat. Namun, semua pembuatan string yang terjadi untuk panggilan ini masih dieksekusi.
  • Aturan utama dalam logging adalah bahwa log Anda tidak boleh mengeluarkan log lain dari buffer secara tidak perlu, sama seperti log lain yang mungkin tidak mengeluarkan log Anda.

Aturan gaya Javatests

Ikuti konvensi penamaan metode pengujian dan gunakan garis bawah untuk memisahkan apa yang sedang diuji dari kasus spesifik yang sedang diuji. Gaya ini memudahkan untuk melihat kasus mana yang sedang diuji. Misalnya:

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))
}