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 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 nguồn mở Android (AOSP). Các đó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ả cá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ả các mã mới đều phải tuân thủ. Xem Mã hóa với sự tôn trọng để biết các ví dụ về thuật ngữ nên sử dụng và tránh cho một hệ sinh thái toàn diện hơn.

Hãy kiên định

Một trong những quy tắc đơn giản nhất là HÃY ĐỒNG Ý. 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 , bạn cũng nên làm như vậy. Nếu các nhận xét mã có các ô nhỏ sao xung quanh chúng, hãy làm cho các nhận xét của bạn cũng có các ô sao nhỏ xung quanh chúng.

Điểm mấu chốt của việc có các hướng dẫn về văn phong là phải có một vốn từ vựng chung về mã hóa, vì vậy người đọc có thể tập trung vào những gì bạn đang nói, thay vì cách bạn đang nói nó. Chúng tôi trình bày các quy tắc về văn phong toàn cầu ở đây để bạn biết từ vựng, nhưng văn phong địa phương cũng rất quan trọng. Nếu mã mà bạn thêm vào tệp trông khác nhiều so với mã hiện có xung quanh nó, nó sẽ khiến người đọc lạc nhịp khi họ đọc nó. 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 trường hợp ngoại lệ

Có thể bị hấp dẫn khi viết mã bỏ qua một ngoại lệ, 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 có thể kích hoạt một ngày nào đó. Bạn phải xử lý mọi ngoại lệ trong mã của mình theo cách có nguyên tắc; việc xử lý cụ thể khác nhau tùy thuộc vào từng trường hợp.

" Bất cứ khi nào ai đó có một điều khoản 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 chính xác phải 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à:

  • Đưa ngoại lệ lên 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 hãy chỉ làm điều đó nếu bạn khẳng định rằng nếu lỗi này xảy ra, điều thích hợp cần làm là 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);
        }
      }
    
  • 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, nhưng bạn cũng phải nêu 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 trường hợp 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ư sau:

  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, không thích hợp để bắt Exception hoặc Throwable chung chung (tốt hơn là không Có thể Throwable vì nó bao gồm các ngoại lệ Error ). Điều đó thật nguy hiểm vì nó 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ệ thời gian chạy như ClassCastException ) bị mắc kẹt trong việc 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, có 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 phải 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 bắt 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 để giữ cho công việc hàng loạt chạy). Trong những trường hợp này, bạn có thể bắt gặp Exception chung (hoặc 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 làm điều 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 giải pháp thay thế để bắt các 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 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.
  • Lặp 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 pháp ném nó đi.

Hãy nhớ rằng các trường hợp 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ó. Mỉm cười! Trình biên dịch chỉ giúp bạn dễ dàng gặp 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

Finalizers là một cách để có một đoạn mã được thực thi khi một đối tượng được thu thập 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 khi nào trình hoàn thiện sẽ được gọi (hoặc thậm chí 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 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 thời điểm phương thức đó cần được gọi (xem InputStream để biết ví dụ). Trong trường hợp này, rất thích hợp nhưng không bắt buộc phải in một thông báo nhật ký ngắn từ trình hoàn thiện, miễn là nó không làm tràn các nhật ký.

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

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

  • import foo.*;

    Có thể làm giảm số lượng báo cáo nhập.

  • import foo.Bar;

    Làm cho nó rõ ràng những gì các lớp được sử dụng và mã dễ đọc hơn cho 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 để 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 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 dùng nữa.

Quy tắc kiểu Java

Sử dụng bình luận chuẩn Javadoc

Mọi tệp phải có 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ả những gì lớp hoặc giao diện thực hiệ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 quan trọng 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.

Các 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 chẳng hạn 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ó một tác dụng phụ quan trọng), thì bạn phải ghi lại nó. Nếu không rõ thuộc tính "Foo" có nghĩa là gì, bạn nên ghi lại tài liệu đó.

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 kiểu 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 pháp 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 pháp dài đôi khi thích hợp, vì vậy không có giới hạn cứng nào được đặt ra đối với độ dài phương thức. Nếu một phương thức vượt quá 40 dòng hoặc lâu hơn, hãy 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 vị trí 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ì của mã của bạn và giảm khả năng xảy ra lỗi. Khai báo mỗi biến trong khối trong cùng chứa tất cả các mục đích sử 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ộ nên chứa một 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.

Ngoại lệ là các 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 ném 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 try. 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());
}

Lệnh nhập khẩu

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

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

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

  • Theo thứ tự bảng chữ cái trong mỗi nhóm, với các chữ cái viết hoa trước các chữ cái 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à 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ì nhập theo cách thủ công. Điều này đã được coi là tồi tệ. Khi kiểu Java được hỏi, các kiểu được ưa thích rất đa dạng và nó đến với 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 kiểu, cập nhật hướng dẫn kiểu và làm cho các IDE tuân theo nó. Chúng tôi hy vọng rằng khi người dùng IDE làm việc trên mã, các lần nhập trong tất cả các gói sẽ khớp với mẫu này mà không cần nỗ lực kỹ thuật thêm.

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

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

Đặt hàng nhập khẩu tĩnh lên trên tất cả các lần nhập khẩu khác được đặt hàng theo cách tương tự như nhập khẩu thông thường.

Sử dụng dấu cách để 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 cá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ề cho các dòng bao trùm, bao gồm cả lệnh gọi và phép gán hàm.

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 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 chữ thường.
  • Các trường cuối cùng tĩnh (hằng số, không thay đổi sâu) 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 dấu ngoặc nhọn 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 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) phải đặt tất cả trên một dòng. Ví dụ, điều này có thể chấp nhận được:

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 thể chấp nhận được:

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ự. Trong khi có nhiều cuộc thảo luận xoay quanh quy tắc này, quyết định vẫn là 100 ký tự là tối đa với các trường hợp ngoại lệ sau :

  • Nếu một dòng chú thích chứa một lệnh mẫu hoặc một URL 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 phải đứng trước các bổ ngữ khác cho cùng một thành phần ngôn ngữ. Chú thích điểm đá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 phần tử 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.

Các phương pháp thực hành 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ử 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à nó phải đặ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 đè 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à dẫn xuấ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 thử nghiệm "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 đều phản ánh các vấn đề thực tế trong mã.

    Khi chú thích @SuppressWarnings là cần thiết, chú thích đó phải được bắt đầu bằng 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ã để cô lập các phần tử phần mềm nơi áp dụng chú thích.

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

Xử lý các từ viết tắt và chữ viết tắt dưới dạng các từ trong cách đặt tên biến, phương thức và lớp để làm cho tên dễ đọc hơn:

Tốt Tồi tệ
XmlHttpRequest XMLHTTPRequest
getCustomerId getCustomerID
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. Do đó, hãy luôn coi các từ viết tắt là từ.

Sử dụng nhận xét CẦN LÀM

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 đượ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ể ("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". ).

Ghi nhật ký 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 lưu giữ hợp lý. Các phương tiện ghi nhật ký cung cấp năm cấp độ ghi nhật ký khác nhau:

  • ERROR : Sử dụng khi một điều gì đó nghiêm trọng đã xảy ra, tức là một đ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 làm mớ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 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 tới máy chủ thu thập thống kê.
  • WARNING : Sử dụng khi điều gì đó nghiêm trọng và không mong muốn đã xảy ra, tức 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ừ đợi hoặc khởi động lại ứng dụng đế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 cho việc ghi nhật ký ở cấp WARNING cũng có thể được xem xét để báo cáo cho máy chủ thu thập thống kê.
  • INFORMATIVE : Sử dụng để lưu ý rằng điều gì đó thú vị đã xảy ra, tức là khi một tình huống được phát hiện có khả năng có tác động rộng rãi, mặc dù không nhất thiết 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 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ó 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 để đ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 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 đang chiếm ưu thế trong nhật ký, thì bạn nên sử dụng ghi nhật ký dài dòng.

    Cấp độ này được ghi lại ngay cả trên các bản dựng phát hành và được yêu cầu bao quanh bởi một 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, do đó có khả năng vô hiệu hóa tất 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 một 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 cho biết if (localLOGV) . Điều này cũng được coi là chấp nhận được, mặc dù tên không đạt tiêu chuẩn.

  • VERBOSE : Sử dụng cho mọi thứ khác. Mức 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 một khối if (LOCAL_LOGV) (hoặc tương đương) để nó có thể được biên dịch theo mặc định. Mọi cấu trúc chuỗi đều bị loại bỏ khỏi các phiên 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, không phải ở cấp VERBOSE , lỗi chỉ nên được báo cáo một lần nếu có thể. Trong một chuỗi lệnh gọi hàm duy nhất 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 cô lập vấn đề một cách đáng kể.
  • Trong một chuỗi các 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, thì mô-đun cấp thấp hơn sẽ chỉ ghi lại 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 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 đang được ghi lại được chứa trong một 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 và các điều kiện gây ra bởi các ứng dụng của bên thứ ba được xử lý đúng cách bởi khung 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 sẽ kích hoạt ghi nhật ký ở cấp INFORMATIVE trở lên là khi một mô-đun hoặc ứng dụng phát hiện ra 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ố bản ghi có khả năng xảy ra nhiều lần, bạn nên triển khai một số cơ chế giới hạn tốc độ để ngăn chặn việc làm tràn các bản ghi 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).
  • 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 nên 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 một ứ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ờ để đăng nhập vào một bản 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 hoặc thay mặt cho các ứng dụng của bên thứ ba sẽ không được ghi lại ở 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 bất kỳ tệp nào 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à sẽ không kích hoạt bất kỳ ghi nhật ký nào ở cấp cao hơn DEBUG khi nó được phát hiện là không hợp lệ (và thậm chí sau đó ghi nhật ký nên 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ử + sẽ 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á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 dựng phát hành, bao gồm cả việc xây dựng các chuỗi, ngay cả khi các bản ghi không được đọc.
  • Bất kỳ nhật ký nào có nghĩa là để người khác đọc và có sẵn trong các bản dựng phát hành phải ngắn gọn mà 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 đế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 đến 80 hoặc 100 ký tự đượ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 ghi nhật ký báo cáo thành công, đừng bao giờ sử dụng nó ở các cấp cao hơn VERBOSE .
  • Nếu bạn đang sử dụ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à gửi kèm theo nếu các khối cho phép tắt nó tại thời điểm biên dịch.
  • Hãy cẩn thận về các rò rỉ bảo mật thông qua nhật ký. Tránh ghi 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ễ dàng biết trước những gì sẽ và sẽ 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 , 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 cuộc gọi này vẫn được thực thi.
  • Quy tắc vàng của việc ghi nhật ký là 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, cũng như những người khác có thể không đẩy các nhật ký của bạn ra.

Quy tắc kiểu Javatests

Tuân theo các quy ước đặt tên của phương pháp thử nghiệm và sử dụng dấu gạch dưới để 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 bạn dễ dàng xem những trường hợp nào đang được kiểm tra. 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))
}