Google cam kết thúc đẩy công bằng chủng tộc cho Cộng đồng người da đen. Xem cách thực hiện.

Kiểu mã AOSP Java dành cho cộng tác viên

Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.

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). Đó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 hy vọng tất cả mã mới sẽ tuân thủ. Xem Mã hóa để 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. 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 phong cách 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 các nhận xét về mã có các hộp sao nhỏ xung quanh chúng, hãy làm cho các nhận xét của bạn cũng có các hộp sao nhỏ xung quanh chúng.

Mục đích của việc có các hướng dẫn về phong cách là có một vốn từ vựng chung về viết mã, để 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 phong cách toàn cầu ở đâ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ã mà bạn thêm vào một tệp trông khác hẳn so với mã hiện có xung quanh nó, nó sẽ khiến người đọc bị lạc nhịp khi đọc. Cố gắng tránh điều này.

Quy tắc ngôn ngữ Java

Android tuân theo các quy ước viết mã 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 theo nguyên tắc; cách 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 cần làm, 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 chấp nhận (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);
      }
    
  • Ném 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 là nguy hiểm, vì vậy chỉ làm điều đó nếu bạn chắc chắn rằng nếu lỗi này xảy ra, điều thích hợp cần làm là làm hỏng máy.
      /** 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 án cuối cùng, nếu bạn tự 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 nhận xét lý do tại sao 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 ngoại lệ chung chung

Có thể lười biếng khi bắt ngoại lệ và làm điều gì đó 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 được là không phù hợp (tốt nhất là không Có thể Throwable được 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 ngoại lệ trong thời gian chạy như ClassCastException ) bị bắt gặp trong 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 đang chạy). Trong những trường hợp này, bạn có thể bắt chung Exception (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 ngữ cảnh này.

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

  • Bắt riêng từng ngoại lệ như một phần của khối bắt nhiều lần, 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 phân tích cú pháp và xử lý lỗi riêng trong từng trường hợp.
  • Rút 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, chỉ cần để phương thức ném nó.

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 nắm bắt các vấn đề về thời gian chạy trong mã của mình dễ dàng hơn.

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

Bộ 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ù bộ 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 khi nào bộ hoàn thiện sẽ được gọi (hoặc thậm chí nó sẽ được gọi).

Android không sử dụng bộ 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 bộ hoàn thiện, hãy xác định phương thức close() (hoặc tương tự) và ghi lại chính xác thời điểm 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 nhật ký 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 được dự kiến ​​sẽ làm ngập 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ó các quy ước để sử dụng các công cụ và thư viện 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 dùng nữa. Khi làm việc với mã như vậy, bạn có thể tiếp tục phong cách 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 dùng nữa.

Quy tắc kiểu Java

Sử dụng các bình luận tiêu chuẩn Javadoc

Mỗi tệp phải có một tuyên bố bản quyền ở trên cùng, tiếp theo là các câu lệnh gói và nhập (mỗi khối được phân tách 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 các nhận xét Javadoc, hãy mô tả chức năng của lớp hoặc giao diện.

/*
 * Copyright 2022 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ừ miêu 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 pháp 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 phương pháp đó. Nếu không rõ thuộc tính "Foo" nghĩa là gì, bạn nên ghi lại thuộc tính đó.

Mọi phương thức bạn viết, công khai hay cách khác, 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 kiểu cụ thể để viết chú thích Javadoc, nhưng bạn nên làm theo hướng dẫn trong Cách viết chú thích 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ỏ và tập trung. Chúng tôi nhận ra rằng các phương thức dài đôi khi thích hợp, do đó không có giới hạn cứng nào được đặt 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 nghĩ xem liệu nó có thể được chia nhỏ mà không làm hại 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à khả năng bảo trì mã của bạn, đồng thời 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 điểm 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ộ phải chứa một trình khởi tạo. Nếu bạn chưa có đủ thông tin để khởi tạo một biến hợp lý, hãy hoãn việc khai báo cho đến khi bạn làm đượ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 một ngoại lệ được kiểm tra, thì nó phải được khởi tạo bên trong một khối thử. Nếu giá trị phải được sử dụng bên ngoài khối thử, thì nó phải được khai báo trước khối thử, 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 hàng đặt hàng

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

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

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

  • Theo thứ tự bảng chữ cái trong mỗi nhóm, với chữ 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ự, nghĩa là các IDE luôn thay đổi thứ tự hoặc cá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 kiểu Java được hỏi, các kiểu ưa thích rất đa dạng và Android chỉ cần "chọn một thứ tự và nhất quán". Vì vậy, chúng tôi đã chọn một phong cách, cập nhật hướng dẫn về phong cách và khiến các IDE tuân theo phong cách đó. Chúng tôi hy vọng rằng khi người dùng IDE làm việc với mã, quá trình nhập trong tất cả các gói sẽ khớp với mẫu này mà không cần thêm nỗ lực kỹ thuật.

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

  • Nội dung nhập mà mọi người muốn xem đầu tiên có xu hướng ở trên cùng ( android ).
  • Nội dung nhập 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ể theo phong cách.

Đặt nhập tĩnh lên trên tất cả các nhập khác được sắp xếp giống như nhập thông thường.

Sử dụng khoảng trắng để thụt đầu dòng

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ờ có 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á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);

Thực hiện theo các 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 một chữ thường.
  • Các trường cuối cùng tĩnh (hằng số, không 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 niềng răng tiêu chuẩn

Đặt dấu ngoặc nhọn trên cùng một 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 báo cáo 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) vừa 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 chấp nhận:

if (condition) body();

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

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

Chiều dài đường giới hạn

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, quyết định vẫn là 100 ký tự là tối đa với các ngoại lệ sau :

  • Nếu một dòng nhận xét chứa một lệnh ví dụ hoặc một 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 đơ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 nên đi trước các công cụ sửa đổi khác cho cùng một thành phần ngôn ngữ. 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 trên mỗi dòng theo thứ tự bảng chữ cái.

Thực tiễn 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ó @deprecated Javadoc 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ó @deprecated Javadoc, 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 đè khai báo hoặc triển khai từ một lớp cha. 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ì chú thích @SuppressWarnings phải được sử dụng để đảm bảo rằng tất cả các cảnh báo phản ánh các sự cố thực tế trong mã.

    Khi chú thích @SuppressWarnings là cần thiết, nó phải được thêm vào đầu chú thích 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 phần tử phần mềm áp dụng chú thích.

Coi từ viết tắt là từ

Coi các từ viết tắt và từ viết tắt là 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 XMLHTTPYêu cầu
getCustomerId lấy ID 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 xung quanh các từ viết tắt, nên hầu như không thể nhất quán với mã xung quanh. Do đó, hãy luôn coi 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 không hoàn hảo. Những nhận xét này phải bao gồm chuỗi TODO 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 ở dạng "Vào một ngày trong tương lai, hãy làm gì đó", hãy đảm bảo rằng bạn bao gồm một ngày cụ thể ("Khắc phục 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ù 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 hợp lý. Các tiện ích 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, nghĩa là điều gì đó sẽ gây ra hậu quả mà người dùng có thể nhìn thấy 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). Cấp độ này luôn được ghi lại. Các vấn đề biện minh cho một số ghi nhật ký ở cấp độ ERROR là những ứng cử viên tốt để được báo cáo cho 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, nghĩa là điều gì đó sẽ gây ra hậu quả mà người dùng có thể nhìn thấy nhưng có khả năng khôi phục được mà không bị 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ị. Cấp độ này luôn được ghi lại. Các vấn đề biện minh cho việc ghi nhật ký ở mức WARNING cũng có thể được xem xét để báo cáo cho máy chủ thu thập số liệu thống kê.
  • INFORMATIVE : Sử dụng để lưu ý rằng một điều gì đó thú vị đã xảy ra, nghĩa là khi một tình huống được phát hiện có thể có tác động lan rộng, mặc dù không nhất thiết phải là lỗi. Điều kiện như vậy chỉ nên được ghi lại bởi một mô-đun tin rằng đó là điều kiện có thẩm quyền nhất trong miền đó (để tránh ghi nhật ký trùng lặp bởi các thành phần không có thẩm quyền). Cấp độ 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 để điều tra và gỡ lỗi các hành vi không mong muốn. Chỉ ghi nhật ký những gì cần thiết để thu thập đủ thông tin về những gì đang diễn 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 ghi nhật ký chi tiết.

    Mức này được ghi lại ngay cả trên các bản phát hành và được yêu cầu 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 con 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ả chuỗi xây dựng 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 đăng nhập thành lệnh gọi phương thức nếu nó sẽ 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. Mức này chỉ được ghi vào 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 ra theo mặc định. Bất kỳ bản dựng chuỗi nào 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 , một lỗi chỉ nên được báo cáo một lần nếu có thể. Trong một chuỗi các 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ố nhật ký nếu điều đó giúp cô lập vấn đề một cách đáng kể.
  • Trong một chuỗi các mô-đun, ngoà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, thì 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 không có sẵn cho người gọi. Cụ thể, không cần phải ghi lại các tình huống khi một ngoại lệ được đưa ra (ngoại lệ này 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 chứa trong một mã lỗi. Điều này đặc biệt quan trọng trong tương tác giữa khung và ứng dụng, đồng thời các tình trạng gây ra bởi ứng dụng bên thứ ba được khung xử lý đúng cách sẽ không kích hoạt ghi nhật ký cao hơn mức DEBUG . Các tình huống duy nhất nên kích hoạt ghi nhật ký ở cấp INFORMATIVE hoặc cao hơn là khi một 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 một số lần ghi nhật ký có khả năng xảy ra nhiều lần, thì nên thực hiện một số cơ chế giới hạn tốc độ để ngăn chặn tràn nhật ký với nhiều bản sao trùng lặp của thông tin giống nhau (hoặc rất giống nhau).
  • Mất kết nối mạng được coi là phổ biến và hoàn toàn có thể xảy ra, đồng thời không được ghi lại một cách vô cớ. Việc mất kết nối mạng dẫn đến 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ờ để ghi vào bản phát hành hay không).
  • Việc có một hệ thống tệp đầy đủ trên một hệ thống tệp mà ứng dụng bên thứ ba có thể truy cập hoặc thay mặt cho các ứng dụng bên thứ ba không được ghi nhật ký ở cấp độ cao hơn INFORMATIVE.
  • 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ự 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 được phát hiện là không hợp lệ (và thậm chí sau đó ghi nhật ký càng hạn chế càng tốt).
  • Khi được sử dụng trên các đối tượng String , toán tử + ngầm tạo một thể hiện 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 tạo chuỗi, ngay cả khi nhật ký không được đọc.
  • Bất kỳ nhật ký nào để người khác đọc và có sẵn trong các bản phát hành 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ả các đăng nhập đến mức DEBUG .
  • Khi có thể, hãy tiếp tục đăng nhập trên một dòng. Độ dài dòng lên tới 80 hoặc 100 ký tự được chấp nhận. Tránh độ 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 ghi nhật ký báo cáo thành công, khô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 một sự cố khó tái tạo, hãy giữ nó ở mức DEBUG hoặc VERBOSE và gửi kèm theo các khối if cho phép vô hiệu hóa nó 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 lại 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 điều gì sẽ và không phải là thông tin cá nhân 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 , vì vậy các câu lệnh in của bạn không có hiệu ứng hiển thị. Tuy nhiên, tất cả việc xây dựng chuỗi xảy ra đối với các cuộc 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à các nhật ký của bạn không được đẩy các nhật ký khác ra khỏi bộ đệm một cách không cần thiết, giống như những người khác không được đẩy các nhật ký của bạn ra.

Quy tắc kiểu 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 nội dung đang được thử nghiệm với trường hợp cụ thể đang được thử nghiệm. Phong cách này giúp dễ dàng 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))
}