Kiểu mã Java AOSP dành cho người đóng góp

Các kiểu mã trên trang này là các quy tắc nghiêm ngặt để đóng góp mã Java cho Dự án mã nguồn mở Android (AOSP). Những đóng góp cho nền tảng Android không tuân thủ các quy tắc này thường không được chấp nhận . Chúng tôi nhận thấy rằng không phải tất cả mã hiện có đều tuân theo các quy tắc này nhưng chúng tôi mong đợi tất cả mã mới đều tuân thủ. Xem Mã hóa liên quan để biết các ví dụ về thuật ngữ nên sử dụng và tránh để có một hệ sinh thái toàn diện hơn.

Hãy nhất quán

Một trong những quy tắc đơn giản nhất là HÃY KIÊN ĐỊNH. Nếu bạn đang chỉnh sửa mã, hãy dành vài phút để xem mã xung quanh và xác định kiểu của nó. Nếu mã đó sử dụng khoảng trắng xung quanh mệnh đề if thì bạn cũng nên làm như vậy. Nếu nhận xét mã có các hộp ngôi sao nhỏ xung quanh, hãy làm cho nhận xét của bạn cũng có các hộp ngôi sao nhỏ xung quanh.

Mục đích của việc có các nguyên tắc về văn phong là phải có vốn từ vựng chung về mã hóa, để người đọc có thể tập trung vào những gì bạn đang nói hơn là vào cách bạn nói. Chúng tôi trình bày các quy tắc văn phong chung ở đây để bạn biết từ vựng, nhưng phong cách địa phương cũng rất quan trọng. Nếu mã bạn thêm vào tệp trông khác biệt nhiều so với mã hiện có xung quanh nó, nó sẽ khiến người đọc mất nhịp khi đọc. Hãy cố gắng tránh điều này.

Quy tắc ngôn ngữ Java

Android tuân theo các quy ước mã hóa Java tiêu chuẩn với các quy tắc bổ sung được mô tả bên dưới.

Đừng bỏ qua các ngoại lệ

Việc viết mã bỏ qua một ngoại lệ có thể rất hấp dẫn, chẳng hạn như:

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

Đừng làm điều này. Mặc dù bạn có thể nghĩ rằng mã của mình sẽ không bao giờ gặp phải tình trạng lỗi này hoặc việc xử lý nó không quan trọng, nhưng việc bỏ qua loại ngoại lệ này sẽ tạo ra các mỏ trong mã của bạn để người khác kích hoạt vào một ngày nào đó. Bạn phải xử lý mọi ngoại lệ trong mã của mình một cách có nguyên tắc; việc xử lý cụ thể khác nhau tùy theo từng trường hợp.

" Bất cứ khi nào ai đó có một mệnh đề bắt trống, họ sẽ có cảm giác rùng rợn. Chắc chắn có những lúc đó thực sự là điều đúng đắn, nhưng ít nhất bạn phải nghĩ về nó. Trong Java, bạn không thể thoát khỏi cảm giác rùng rợn. "-James Gosling

Các lựa chọn thay thế có thể chấp nhận được (theo thứ tự ưu tiên) là:

  • Ném ngoại lệ cho người gọi phương thức của bạn.
      void setServerPort(String value) throws NumberFormatException {
          serverPort = Integer.parseInt(value);
      }
    
  • Đưa ra một ngoại lệ mới phù hợp với mức độ trừu tượng của bạn.
      void setServerPort(String value) throws ConfigurationException {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new ConfigurationException("Port " + value + " is not valid.");
        }
      }
    
  • Xử lý lỗi một cách khéo léo và thay thế một giá trị thích hợp trong khối 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
        }
      }
    
  • Bắt ngoại lệ và ném một phiên bản mới của RuntimeException . Điều này rất nguy hiểm, vì vậy chỉ thực hiện nếu bạn khẳng định rằng nếu lỗi này xảy ra thì điều thích hợp cần làm là gặp sự cố.
      /** 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);
        }
      }
    
  • Phương sách cuối cùng, nếu bạn tin rằng việc bỏ qua ngoại lệ là phù hợp thì bạn có thể bỏ qua nó, nhưng bạn cũng phải bình luận lý do với lý do chính đáng.
    /** 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.
        }
    }
    

Đừng bắt những ngoại lệ chung chung

Bạn có thể lười biếng khi bắt các ngoại lệ và làm những việc như thế này:

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

Đừng làm điều này. Trong hầu hết các trường hợp, việc bắt Exception chung hoặc Throwable là không phù hợp (tốt nhất là không Throwable vì nó bao gồm các ngoại lệ Error ). Điều này nguy hiểm vì điều đó có nghĩa là các ngoại lệ mà bạn không bao giờ mong đợi (bao gồm cả các ngoại lệ trong thời gian chạy như ClassCastException ) bị vướng vào quá trình xử lý lỗi cấp ứng dụng. Nó che khuất các thuộc tính xử lý lỗi trong mã của bạn, nghĩa là nếu ai đó thêm một loại ngoại lệ mới vào mã bạn đang gọi, trình biên dịch sẽ không chỉ ra rằng bạn cần xử lý lỗi theo cách khác. Trong hầu hết các trường hợp, bạn không nên xử lý các loại ngoại lệ khác nhau theo cùng một cách.

Ngoại lệ hiếm hoi đối với quy tắc này là mã kiểm tra và mã cấp cao nhất mà bạn muốn phát hiện tất cả các loại lỗi (để ngăn chúng hiển thị trong giao diện người dùng hoặc để duy trì công việc hàng loạt). Trong những trường hợp này, bạn có thể bắt gặp Exception chung (hoặc Throwable ) và xử lý lỗi một cách thích hợp. Tuy nhiên, hãy suy nghĩ cẩn thận trước khi thực hiện việc này và đưa ra nhận xét giải thích lý do tại sao nó an toàn trong bối cảnh này.

Các lựa chọn thay thế để bắt ngoại lệ chung:

  • Bắt từng ngoại lệ riêng biệt như một phần của khối đa bắt, ví dụ:
    try {
        ...
    } catch (ClassNotFoundException | NoSuchMethodException e) {
        ...
    }
  • Cấu trúc lại mã của bạn để xử lý lỗi chi tiết hơn với nhiều khối thử. Tách IO khỏi quá trình phân tích cú pháp và xử lý các lỗi riêng biệt trong từng trường hợp.
  • Ném lại ngoại lệ. Nhiều khi bạn không cần phải bắt ngoại lệ ở cấp độ này, cứ để phương thức ném nó đi.

Hãy nhớ rằng ngoại lệ là bạn của bạn! Khi trình biên dịch phàn nàn rằng bạn không bắt được ngoại lệ, đừng cau có. Nụ cười! Trình biên dịch chỉ giúp bạn dễ dàng nắm bắt các vấn đề về thời gian chạy trong mã của mình hơn.

Không sử dụng công cụ hoàn thiện

Công cụ hoàn thiện là một cách để thực thi một đoạn mã khi một đối tượng được thu gom rác. Mặc dù trình hoàn thiện có thể hữu ích cho việc dọn dẹp (đặc biệt là các tài nguyên bên ngoài), nhưng không có gì đảm bảo về thời điểm trình hoàn thiện sẽ được gọi (hoặc thậm chí là nó sẽ được gọi).

Android không sử dụng công cụ hoàn thiện. Trong hầu hết các trường hợp, bạn có thể sử dụng cách xử lý ngoại lệ tốt để thay thế. Nếu bạn thực sự cần một trình hoàn thiện, hãy xác định một phương thức close() (hoặc tương tự) và ghi lại chính xác khi nào phương thức đó cần được gọi (xem Ví dụ về inputStream ). Trong trường hợp này, việc in một thông báo tường trình ngắn từ trình hoàn thiện là phù hợp nhưng không bắt buộc, miễn là nó không làm tràn nhật ký.

Nhập khẩu đủ điều kiện

Khi bạn muốn sử dụng lớp Bar từ gói foo , có hai cách để nhập nó:

  • import foo.*;

    Có khả năng làm giảm số lượng báo cáo nhập khẩu.

  • import foo.Bar;

    Làm rõ những lớp nào được sử dụng và mã dễ đọc hơn đối với người bảo trì.

Sử dụng import foo.Bar; để nhập tất cả mã Android. Một ngoại lệ rõ ràng được tạo cho các thư viện chuẩn Java ( java.util.* , java.io.* , v.v.) và mã kiểm tra đơn vị ( junit.framework.* ).

Quy tắc thư viện Java

Có những quy ước về sử dụng các thư viện và công cụ Java của Android. Trong một số trường hợp, quy ước đã thay đổi theo những cách quan trọng và mã cũ hơn có thể sử dụng mẫu hoặc thư viện không được dùng nữa. Khi làm việc với mã như vậy, bạn có thể tiếp tục kiểu hiện có. Tuy nhiên, khi tạo các thành phần mới, đừng bao giờ sử dụng các thư viện không được dùng nữa.

Quy tắc kiểu Java

Sử dụng nhận xét tiêu chuẩn Javadoc

Mỗi tệp phải có tuyên bố bản quyền ở trên cùng, theo sau là các câu lệnh gói và nhập (mỗi khối cách nhau bằng một dòng trống) và cuối cùng là khai báo lớp hoặc giao diện. Trong phần nhận xét Javadoc, hãy mô tả chức năng của lớp hoặc giao diện đó.

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

Mỗi lớp và phương thức công khai không cần thiết mà bạn viết phải chứa một nhận xét Javadoc với ít nhất một câu mô tả chức năng của lớp hoặc phương thức đó. Câu này nên bắt đầu bằng động từ mô tả ngôi thứ ba.

Ví dụ

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

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

hoặc

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

Bạn không cần phải viết Javadoc cho các phương thức get và set tầm thường như setFoo() nếu tất cả Javadoc của bạn sẽ nói là "sets Foo". Nếu phương thức thực hiện điều gì đó phức tạp hơn (chẳng hạn như thực thi một ràng buộc hoặc có tác dụng phụ quan trọng), thì bạn phải ghi lại nó. Nếu thuộc tính "Foo" nghĩa là gì không rõ ràng, bạn nên ghi lại nó.

Mọi phương thức bạn viết, công khai hay cách khác, đều sẽ được hưởng lợi từ Javadoc. Các phương thức công khai là một phần của API và do đó yêu cầu Javadoc. Android không thực thi một phong cách cụ thể để viết nhận xét Javadoc, nhưng bạn nên làm theo hướng dẫn trong Cách viết nhận xét tài liệu cho Công cụ Javadoc .

Viết các phương thức ngắn

Khi khả thi, hãy giữ các phương pháp nhỏ gọn và tập trung. Chúng tôi nhận thấy rằng các phương thức dài đôi khi thích hợp nên không có giới hạn cố định nào được đặt ra cho độ dài của phương thức. Nếu một phương thức vượt quá 40 dòng hoặc hơn, hãy suy nghĩ xem liệu nó có thể được chia nhỏ mà không làm tổn hại đến cấu trúc của chương trình hay không.

Xác định các trường ở những nơi tiêu chuẩn

Xác định các trường ở đầu tệp hoặc ngay trước các phương thức sử dụng chúng.

Giới hạn phạm vi biến

Giữ phạm vi của các biến cục bộ ở mức tối thiểu. Điều này làm tăng khả năng đọc và bảo trì mã của bạn và giảm khả năng xảy ra lỗi. Khai báo từng biến trong khối trong cùng bao gồm tất cả các công dụng của biến đó.

Khai báo các biến cục bộ tại thời điểm chúng được sử dụng lần đầu tiên. Gần như mọi khai báo biến cục bộ đều phải chứa bộ khởi tạo. Nếu bạn chưa có đủ thông tin để khởi tạo một biến một cách hợp lý, hãy hoãn việc khai báo cho đến khi bạn thực hiện được.

Ngoại lệ là câu lệnh try-catch. Nếu một biến được khởi tạo với giá trị trả về của một phương thức đưa ra ngoại lệ đã kiểm tra, thì biến đó phải được khởi tạo bên trong khối thử. Nếu giá trị phải được sử dụng bên ngoài khối try thì nó phải được khai báo trước khối try, nơi nó chưa thể được khởi tạo một cách hợp lý:

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

Tuy nhiên, bạn thậm chí có thể tránh trường hợp này bằng cách đóng gói khối try-catch trong một phương thức:

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

Khai báo các biến vòng lặp trong chính câu lệnh for trừ khi có lý do thuyết phục để làm khác:

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

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

Báo cáo nhập lệnh

Thứ tự của các báo cáo nhập khẩu là:

  1. Nhập khẩu Android
  2. Nhập khẩu từ bên thứ ba ( com , junit , net , org )
  3. javajavax

Để khớp chính xác với cài đặt IDE, nội dung nhập phải là:

  • Theo thứ tự bảng chữ cái trong mỗi nhóm, với chữ in hoa trước chữ thường (ví dụ: Z trước a)
  • Được phân tách bằng một dòng trống giữa mỗi nhóm chính ( android , com , junit , net , org , java , javax )

Ban đầu, không có yêu cầu về kiểu dáng đối với thứ tự, có nghĩa là các IDE luôn thay đổi thứ tự hoặc nhà phát triển IDE phải tắt các tính năng quản lý nhập tự động và duy trì việc nhập theo cách thủ công. Điều này được coi là xấu. Khi phong cách Java được hỏi, các kiểu ưa thích rất đa dạng và Android chỉ cần "chọn thứ tự và nhất quán". Vì vậy, chúng tôi đã chọn một kiểu, cập nhật hướng dẫn về kiểu và yêu cầu các IDE tuân theo kiểu đó. Chúng tôi hy vọng rằng khi người dùng IDE làm việc với mã, việc nhập vào tất cả các gói sẽ khớp với mẫu này mà không cần nỗ lực thêm về mặt kỹ thuật.

Chúng tôi đã chọn phong cách này sao cho:

  • Những mặt hàng nhập khẩu mà mọi người muốn xem xét đầu tiên thường có xu hướng đứng đầu ( android ).
  • Những mặt hàng nhập khẩu mà mọi người muốn xem ít nhất có xu hướng ở dưới cùng ( java ).
  • Con người có thể dễ dàng làm theo phong cách.
  • IDE có thể làm theo phong cách.

Đặt hàng nhập khẩu tĩnh lên trên tất cả các mặt hàng nhập khẩu khác được đặt hàng giống như hàng nhập khẩu thông thường.

Sử dụng khoảng trắng để thụt lề

Chúng tôi sử dụng bốn (4) khoảng cách thụt lề cho các khối và không bao giờ cho tab. Khi nghi ngờ, hãy nhất quán với mã xung quanh.

Chúng tôi sử dụng tám (8) khoảng cách thụt lề để ngắt dòng, bao gồm cả lệnh gọi hàm và phép gán.

Khuyến khích

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

Không được khuyến khích

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

Tuân theo quy ước đặt tên trường

  • Tên trường không công khai, không tĩnh bắt đầu bằng m .
  • Tên trường tĩnh bắt đầu bằng s .
  • Các trường khác bắt đầu bằng chữ cái viết thường.
  • Các trường cuối cùng tĩnh (hằng số, không thể thay đổi sâu sắc) là ALL_CAPS_WITH_UNDERSCORES .

Ví dụ:

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

Sử dụng kiểu nẹp tiêu chuẩn

Đặt các dấu ngoặc nhọn trên cùng dòng với mã trước chúng, không phải trên dòng riêng của chúng:

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

Chúng tôi yêu cầu dấu ngoặc nhọn xung quanh các câu lệnh cho một điều kiện. Ngoại lệ: Nếu toàn bộ điều kiện (điều kiện và nội dung) nằm trên một dòng, bạn có thể (nhưng không bắt buộc) đặt tất cả trên một dòng. Ví dụ: điều này được chấp nhận:

if (condition) {
    body();
}

và điều này có thể chấp nhận được:

if (condition) body();

nhưng điều này không được chấp nhận:

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

Giới hạn độ dài dòng

Mỗi dòng văn bản trong mã của bạn phải dài tối đa 100 ký tự. Mặc dù có nhiều cuộc thảo luận xung quanh quy tắc này nhưng quyết định vẫn là 100 ký tự là tối đa với các ngoại lệ sau :

  • Nếu dòng nhận xét chứa lệnh ví dụ hoặc URL bằng chữ dài hơn 100 ký tự thì dòng đó có thể dài hơn 100 ký tự để dễ cắt và dán.
  • Các dòng nhập có thể vượt quá giới hạn vì con người hiếm khi nhìn thấy chúng (điều này cũng giúp đơn giản hóa việc viết công cụ).

Sử dụng các chú thích Java tiêu chuẩn

Chú thích phải đặt trước các công cụ sửa đổi khác cho cùng một thành phần ngôn ngữ. Các chú thích đánh dấu đơn giản (ví dụ: @Override ) có thể được liệt kê trên cùng một dòng với thành phần ngôn ngữ. Nếu có nhiều chú thích hoặc chú thích được tham số hóa, hãy liệt kê chúng từng chú thích trên một dòng theo thứ tự bảng chữ cái.

Các phương pháp tiêu chuẩn của Android cho ba chú thích được xác định trước trong Java là:

  • Sử dụng chú thích @Deprecated bất cứ khi nào việc sử dụng phần tử được chú thích không được khuyến khích. Nếu bạn sử dụng chú thích @Deprecated , bạn cũng phải có thẻ Javadoc @deprecated và thẻ này sẽ đặt tên cho một triển khai thay thế. Ngoài ra, hãy nhớ rằng phương thức @Deprecated vẫn được cho là hoạt động . Nếu bạn thấy mã cũ có thẻ Javadoc @deprecated , hãy thêm chú thích @Deprecated .
  • Sử dụng chú thích @Override bất cứ khi nào một phương thức ghi đè phần khai báo hoặc triển khai từ siêu lớp. Ví dụ: nếu bạn sử dụng thẻ @inheritdocs Javadoc và xuất phát từ một lớp (không phải giao diện), bạn cũng phải chú thích rằng phương thức này sẽ ghi đè phương thức của lớp cha.
  • Chỉ sử dụng chú thích @SuppressWarnings trong những trường hợp không thể loại bỏ cảnh báo. Nếu một cảnh báo vượt qua bài kiểm tra "không thể loại bỏ" này thì phải sử dụng chú thích @SuppressWarnings để đảm bảo rằng tất cả các cảnh báo đều phản ánh các vấn đề thực tế trong mã.

    Khi cần chú thích @SuppressWarnings , chú thích đó phải được bắt đầu bằng nhận xét TODO giải thích điều kiện "không thể loại bỏ". Điều này thường xác định một lớp vi phạm có giao diện khó xử. Ví dụ:

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

    Khi cần có chú thích @SuppressWarnings , hãy cấu trúc lại mã để tách biệt các thành phần phần mềm áp dụng chú thích.

Coi các từ viết tắt như từ

Hãy coi các từ viết tắt và viết tắt như các từ khi đặt tên biến, phương thức và lớp để làm cho tên dễ đọc hơn:

Tốt Xấu
XmlHttpRequest Yêu cầu XMLHTTP
lấyId khách hàng lấyID khách hàng
lớp Html lớp HTML
Url chuỗi URL chuỗi
id dài ID dài

Vì cả cơ sở mã JDK và Android đều không nhất quán về các từ viết tắt nên hầu như không thể nhất quán với mã xung quanh. Vì vậy, hãy luôn coi các từ viết tắt là từ.

Sử dụng nhận xét TODO

Sử dụng nhận xét TODO cho mã tạm thời, giải pháp ngắn hạn hoặc đủ tốt nhưng chưa hoàn hảo. Những nhận xét này phải bao gồm chuỗi TODO được viết hoa toàn bộ, theo sau là dấu hai chấm:

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

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

Nếu TODO của bạn có dạng "Vào một ngày trong tương lai, hãy làm điều gì đó", hãy đảm bảo rằng bạn bao gồm một ngày cụ thể ("Sửa trước tháng 11 năm 2005") hoặc một sự kiện cụ thể ("Xóa mã này sau khi tất cả các bộ trộn sản xuất hiểu giao thức V7." ).

Đăng nhập một cách tiết kiệm

Mặc dù việc ghi nhật ký là cần thiết nhưng nó có tác động tiêu cực đến hiệu suất và mất đi tính hữu dụng nếu không được giữ ngắn gọn một cách hợp lý. Các cơ sở ghi nhật ký cung cấp năm cấp độ ghi nhật ký khác nhau:

  • ERROR : Sử dụng khi điều gì đó nghiêm trọng đã xảy ra, tức là điều gì đó sẽ gây ra hậu quả mà người dùng có thể thấy được và sẽ không thể khôi phục được nếu không xóa một số dữ liệu, gỡ cài đặt ứng dụng, xóa phân vùng dữ liệu hoặc khởi động lại toàn bộ thiết bị (hoặc tệ hơn). Mức này luôn được ghi lại. Các vấn đề chứng minh việc ghi nhật ký ở cấp độ ERROR là những ứng cử viên phù hợp để được báo cáo tới máy chủ thu thập số liệu thống kê.
  • WARNING : Sử dụng khi điều gì đó nghiêm trọng và bất ngờ xảy ra, tức là điều gì đó sẽ gây ra hậu quả mà người dùng có thể thấy nhưng có khả năng phục hồi được mà không mất dữ liệu bằng cách thực hiện một số hành động rõ ràng, từ chờ đợi hoặc khởi động lại ứng dụng cho đến tải xuống lại phiên bản mới của ứng dụng hoặc khởi động lại thiết bị. Mức này luôn được ghi lại. Các vấn đề chứng minh việc ghi nhật ký ở cấp độ WARNING cũng có thể được xem xét để báo cáo tới máy chủ thu thập số liệu thống kê.
  • INFORMATIVE : Sử dụng để lưu ý rằng điều gì đó thú vị đã xảy ra, nghĩa là khi phát hiện ra một tình huống có thể có tác động trên diện rộng, mặc dù không nhất thiết phải là một lỗi. Điều kiện như vậy chỉ nên được ghi lại bởi mô-đun tin rằng đó là điều kiện có thẩm quyền nhất trong miền đó (để tránh việc ghi nhật ký trùng lặp bởi các thành phần không có thẩm quyền). Mức này luôn được ghi lại.
  • DEBUG : Sử dụng để ghi chú thêm những gì đang xảy ra trên thiết bị có thể liên quan đến việc điều tra và gỡ lỗi các hành vi không mong muốn. Chỉ ghi lại những gì cần thiết để thu thập đủ thông tin về những gì đang xảy ra với thành phần của bạn. Nếu nhật ký gỡ lỗi của bạn chiếm ưu thế trong nhật ký thì bạn nên sử dụng tính năng ghi nhật ký chi tiết.

    Cấp độ này được ghi lại ngay cả trên các bản phát hành và bắt buộc phải được bao quanh bởi khối if (LOCAL_LOG) hoặc if LOCAL_LOGD) , trong đó LOCAL_LOG[D] được xác định trong lớp hoặc thành phần phụ của bạn, để có khả năng vô hiệu hóa tất cả việc ghi nhật ký đó . Do đó, không được có logic hoạt động trong khối if (LOCAL_LOG) . Tất cả việc xây dựng chuỗi cho nhật ký cũng cần được đặt bên trong khối if (LOCAL_LOG) . Không cấu trúc lại lệnh gọi ghi nhật ký thành lệnh gọi phương thức nếu điều đó khiến việc xây dựng chuỗi diễn ra bên ngoài khối if (LOCAL_LOG) .

    Có một số mã vẫn nói if (localLOGV) . Điều này cũng được coi là chấp nhận được, mặc dù tên này không chuẩn.

  • VERBOSE : Sử dụng cho mọi thứ khác. Cấp độ này chỉ được ghi lại trên các bản dựng gỡ lỗi và phải được bao quanh bởi khối if (LOCAL_LOGV) (hoặc tương đương) để có thể biên dịch nó theo mặc định. Bất kỳ cấu trúc chuỗi nào đều bị loại bỏ khỏi bản phát hành và cần xuất hiện bên trong khối if (LOCAL_LOGV) .

Ghi chú

  • Trong một mô-đun nhất định, ngoại trừ ở cấp độ VERBOSE , lỗi chỉ được báo cáo một lần nếu có thể. Trong một chuỗi lệnh gọi hàm trong một mô-đun, chỉ hàm trong cùng mới trả về lỗi và những người gọi trong cùng một mô-đun chỉ nên thêm một số ghi nhật ký nếu điều đó giúp ích đáng kể trong việc tách biệt sự cố.
  • Trong chuỗi mô-đun, không phải ở cấp VERBOSE , khi mô-đun cấp thấp hơn phát hiện dữ liệu không hợp lệ đến từ mô-đun cấp cao hơn, mô-đun cấp thấp hơn chỉ nên ghi tình huống này vào nhật ký DEBUG và chỉ khi việc ghi nhật ký cung cấp thông tin mà người gọi không có sẵn. Cụ thể, không cần ghi lại các tình huống trong đó một ngoại lệ được đưa ra (ngoại lệ phải chứa tất cả thông tin liên quan) hoặc khi thông tin duy nhất được ghi lại được chứa trong mã lỗi. Điều này đặc biệt quan trọng trong sự tương tác giữa khung và ứng dụng, đồng thời các điều kiện do ứng dụng bên thứ ba được khung xử lý đúng cách gây ra sẽ không kích hoạt ghi nhật ký cao hơn cấp DEBUG . Các tình huống duy nhất sẽ kích hoạt ghi nhật ký ở cấp INFORMATIVE trở lên là khi mô-đun hoặc ứng dụng phát hiện lỗi ở cấp độ của chính nó hoặc đến từ cấp độ thấp hơn.
  • Khi một điều kiện thường biện minh cho việc ghi nhật ký có khả năng xảy ra nhiều lần, có thể nên triển khai một số cơ chế giới hạn tốc độ để tránh làm tràn nhật ký với nhiều bản sao trùng lặp của cùng một thông tin (hoặc rất giống nhau).
  • Việc mất kết nối mạng được coi là phổ biến và hoàn toàn có thể xảy ra và không được ghi lại một cách vô cớ. Việc mất kết nối mạng gây ra hậu quả trong ứng dụng phải được ghi lại ở cấp độ DEBUG hoặc VERBOSE (tùy thuộc vào việc hậu quả có đủ nghiêm trọng và đủ bất ngờ để được ghi vào bản dựng phát hành hay không).
  • Việc có hệ thống tệp đầy đủ trên hệ thống tệp có thể truy cập được hoặc thay mặt cho các ứng dụng của bên thứ ba không được ghi nhật ký ở cấp độ cao hơn THÔNG TIN.
  • Dữ liệu không hợp lệ đến từ bất kỳ nguồn không đáng tin cậy nào (bao gồm mọi tệp trên bộ nhớ dùng chung hoặc dữ liệu đến qua kết nối mạng) được coi là dữ liệu dự kiến ​​và không được kích hoạt bất kỳ hoạt động ghi nhật ký nào ở mức cao hơn DEBUG khi nó được phát hiện là không hợp lệ (và thậm chí sau đó việc ghi nhật ký sẽ không hợp lệ). nên hạn chế nhất có thể).
  • Khi được sử dụng trên các đối tượng String , toán tử + ngầm tạo một cá thể StringBuilder với kích thước bộ đệm mặc định (16 ký tự) và có thể là các đối tượng String tạm thời khác. Vì vậy, việc tạo các đối tượng StringBuilder một cách rõ ràng không đắt hơn việc dựa vào toán tử + mặc định (và có thể hiệu quả hơn rất nhiều). Hãy nhớ rằng mã gọi Log.v() được biên dịch và thực thi trên các bản phát hành, bao gồm cả việc xây dựng chuỗi, ngay cả khi nhật ký không được đọc.
  • Bất kỳ nhật ký nào nhằm mục đích để người khác đọc và có sẵn trong các bản phát hành đều phải ngắn gọn, không khó hiểu và phải dễ hiểu. Điều này bao gồm tất cả việc đăng nhập lên cấp DEBUG .
  • Khi có thể, hãy tiếp tục đăng nhập trên một dòng duy nhất. Độ dài dòng lên tới 80 hoặc 100 ký tự đều được chấp nhận. Tránh độ dài dài hơn khoảng 130 hoặc 160 ký tự (bao gồm cả độ dài của thẻ) nếu có thể.
  • Nếu việc ghi nhật ký báo cáo thành công, đừng bao giờ sử dụng nó ở cấp độ cao hơn VERBOSE .
  • Nếu bạn đang sử dụng tính năng ghi nhật ký tạm thời để chẩn đoán sự cố khó tái tạo, hãy giữ nó ở mức DEBUG hoặc VERBOSE và kèm theo các khối nếu cho phép vô hiệu hóa sự cố đó tại thời điểm biên dịch.
  • Hãy cẩn thận về rò rỉ bảo mật thông qua nhật ký. Tránh đăng nhập thông tin cá nhân. Đặc biệt, tránh ghi thông tin về nội dung được bảo vệ. Điều này đặc biệt quan trọng khi viết mã khung vì không dễ để biết trước những gì sẽ và không phải là thông tin riêng tư hoặc nội dung được bảo vệ.
  • Không bao giờ sử dụng System.out.println() (hoặc printf() cho mã gốc). System.outSystem.err được chuyển hướng đến /dev/null , do đó các câu lệnh in của bạn không có hiệu ứng rõ ràng. Tuy nhiên, tất cả việc xây dựng chuỗi xảy ra cho các lệnh gọi này vẫn được thực thi.
  • Nguyên tắc vàng của việc ghi nhật ký là nhật ký của bạn không được đẩy nhật ký khác ra khỏi bộ đệm một cách không cần thiết, cũng như những người khác không được đẩy nhật ký của bạn ra.

Quy tắc phong cách Javatests

Thực hiện theo các quy ước đặt tên phương pháp thử nghiệm và sử dụng dấu gạch dưới để phân tách những gì đang được thử nghiệm khỏi trường hợp cụ thể đang được thử nghiệm. Phong cách này giúp dễ dàng hơn để xem trường hợp nào đang được thử nghiệm. Ví dụ:

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