รูปแบบโค้ดในหน้านี้เป็นกฎที่เข้มงวดสำหรับการส่งโค้ด Java ไปยัง โครงการโอเพนซอร์ส Android (AOSP) การมีส่วนร่วมในแพลตฟอร์ม Android ที่ไม่ปฏิบัติตามกฎเหล่านี้มักจะไม่ได้รับการยอมรับ พ โปรดทราบว่าโค้ดที่มีอยู่บางโค้ดไม่ได้ปฏิบัติตามกฎเหล่านี้ แต่เราคาดหวังว่า เพื่อให้สอดคล้องกับข้อกำหนด ดูการเขียนโค้ดด้วยความเคารพ สำหรับตัวอย่างคำศัพท์ที่ควรใช้และหลีกเลี่ยงในระบบนิเวศที่ไม่แบ่งแยกมากขึ้น
มีความสม่ำเสมอ
หนึ่งในกฎที่ง่ายที่สุดคือมีความสอดคล้องกัน หากคุณกำลังแก้ไขโค้ด ให้ใช้
นาทีเพื่อดูโค้ดโดยรอบและกำหนดรูปแบบ หากเป็นเช่นนั้น
คุณควรใช้ช่องว่างรอบๆ วลี if
ด้วย หากโค้ด
ความคิดเห็นของคุณมีดาวล้อมรอบ ทำให้ความคิดเห็นของคุณมีดาว
และมีดาวล้อมรอบตัวเล็กๆ อยู่ด้วย
จุดประสงค์ของหลักเกณฑ์รูปแบบคือการมีคำศัพท์ทั่วไปที่ เขียนโค้ด เพื่อให้ผู้อ่านมีสมาธิกับสิ่งที่คุณพูด แทนที่จะเขียน จะพูดยังไง เราแสดงกฎของรูปแบบสากลที่นี่เพื่อให้คุณทราบว่า คำศัพท์ แต่สไตล์ท้องถิ่นก็สำคัญเช่นกัน หากโค้ดที่คุณเพิ่ม ไฟล์ดูแตกต่างจากโค้ดที่มีอยู่รอบๆ ไฟล์อย่างมาก ทำให้ผู้อ่านรู้สึกผิดจังหวะเมื่ออ่าน พยายาม เพื่อหลีกเลี่ยงเรื่องนี้
กฎภาษา Java
Android เป็นไปตามแบบแผนการเขียนโค้ด Java มาตรฐานโดยมีกฎเพิ่มเติม ดังที่อธิบายไว้ด้านล่าง
ไม่ต้องละเว้นข้อยกเว้น
คุณอาจจะอยากเขียนโค้ดโดยไม่คำนึงถึงข้อยกเว้น เช่น
void setServerPort(String value) { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { } }
โปรดอย่าทำ แม้คุณอาจคิดว่าโค้ดของคุณจะไม่พบปัญหานี้ หรือข้อผิดพลาดที่ไม่จำเป็นต้องจัดการ โดยละเลยข้อผิดพลาดประเภทนี้ ข้อยกเว้นสร้างกับระเบิดในโค้ดของคุณให้คนอื่น กระตุ้นสักวัน คุณต้องจัดการข้อยกเว้นทั้งหมดในโค้ดของคุณใน ตามหลักการ วิธีการจัดการบางอย่างจะแตกต่างกันไป ขึ้นอยู่กับแต่ละกรณี
"ทุกครั้งที่ใครมีประโยคเด็ดๆ ที่ขาดๆ หายๆ ก็คงจะน่ากลัว ความรู้สึก แต่ก็มีบางคราวที่เว็บไซต์ของเราถูก ที่ควรทำ แต่อย่างน้อยคุณก็ต้องคิดให้ดี ใน Java คุณไม่สามารถ หลีกหนีความรู้สึกน่ากลัว" - เจมส์ ลูกหมาก
ทางเลือกที่ยอมรับได้ (ตามลำดับที่ต้องการ) ได้แก่
- ส่งข้อยกเว้นให้ผู้โทรที่ใช้วิธีการดังกล่าว
void setServerPort(String value) throws NumberFormatException { serverPort = Integer.parseInt(value); }
-
ส่งข้อยกเว้นใหม่ที่เหมาะสมกับระดับ Abstraction ของคุณ
void setServerPort(String value) throws ConfigurationException { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { throw new ConfigurationException("Port " + value + " is not valid."); } }
-
จัดการกับข้อผิดพลาดอย่างสวยงามและใช้ค่าที่เหมาะสมใน
บล็อก
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 } }
-
รับข้อยกเว้นและส่งอินสแตนซ์ใหม่ของ
RuntimeException
สิ่งนี้อันตราย โปรดทำเฉพาะเมื่อคุณมั่นใจว่าถ้าสิ่งนี้ สิ่งที่เหมาะสมคือการขัดข้อง/** 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); } }
-
ทางเลือกสุดท้าย ถ้าคุณมั่นใจว่า การละเว้นข้อยกเว้น
คุณไม่จำเป็นต้องสนใจสิ่งนั้น แต่คุณก็ต้องให้เหตุผลด้วย
มีเหตุผลที่ดี
/** 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. } }
ไม่ตรวจจับข้อยกเว้นทั่วไป
คุณอาจจะเป็นคนขี้เกียจเมื่อต้องมองหาข้อยกเว้นและทำ ประมาณนี้
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! }
โปรดอย่าทำ ในเกือบทุกกรณี การจับผิดทั่วไปนั้นเป็นสิ่งที่ไม่เหมาะสม
Exception
หรือ Throwable
(ไม่ควรเป็น Throwable
เนื่องจากมี
ข้อยกเว้น Error
รายการ) เป็นอันตราย เนื่องจากหมายความว่าอาจมีข้อยกเว้น
ที่คุณคาดไม่ถึง (รวมถึงข้อยกเว้นรันไทม์อย่าง ClassCastException
)
เจอในการจัดการข้อผิดพลาดระดับแอป ซึ่งปกปิดความล้มเหลว
การจัดการคุณสมบัติต่างๆ ของโค้ด ซึ่งหมายความว่าหากมีผู้เพิ่มประเภท
ในโค้ดที่คุณเรียกใช้ คอมไพเลอร์จะไม่ระบุ
ในการจัดการข้อผิดพลาดให้แตกต่างออกไปได้ ในกรณีส่วนใหญ่ คุณ
ไม่ควรจัดการข้อยกเว้นประเภทต่างๆ ในลักษณะเดียวกัน
ข้อยกเว้นที่พบไม่บ่อยนักสำหรับกฎนี้คือโค้ดทดสอบและโค้ดระดับบนสุดที่
คุณต้องการหาข้อผิดพลาดทุกประเภท (เพื่อป้องกันไม่ให้ระบบแสดง
ใน UI หรือเพื่อให้งานแบบกลุ่มทำงานต่อไป) ในกรณีเช่นนี้ คุณอาจเห็นว่า
Exception
แบบทั่วไป (หรือ Throwable
) และจัดการข้อผิดพลาดอย่างเหมาะสม
อย่างไรก็ตาม โปรดคิดให้รอบคอบก่อนที่จะดำเนินการนี้ และแสดงความคิดเห็น
อธิบายถึงเหตุผลที่วิธีนี้ปลอดภัยในบริบทนี้
ทางเลือกอื่นที่สามารถใช้เพื่อตรวจจับข้อยกเว้นทั่วไปมีดังนี้
-
ระบุข้อยกเว้นแต่ละรายการแยกกันในการบล็อกแบบมัลติแคตช์ เช่น
try { ... } catch (ClassNotFoundException | NoSuchMethodException e) { ... }
- เปลี่ยนโครงสร้างภายในโค้ดเพื่อให้จัดการกับข้อผิดพลาดได้ละเอียดยิ่งขึ้นด้วย การลองบล็อกหลายครั้ง แยก IO จากการแยกวิเคราะห์และจัดการข้อผิดพลาด แยกกันในแต่ละกรณี
- ส่งข้อยกเว้นอีกครั้ง หลายๆ ครั้งคุณไม่จำเป็นต้องจับ ที่การยกเว้นที่ระดับนี้ ปล่อยให้เมธอดส่ง
อย่าลืมว่าข้อยกเว้นคือข้อจำกัดสำหรับคุณ เมื่อผู้คอมไพเลอร์บ่นว่าคุณ เพื่อตรวจหาข้อยกเว้น อย่าทำหน้าบึ้ง ยิ้มหน่อย คอมไพเลอร์เพิ่งสร้าง ทำให้คุณจับปัญหารันไทม์ในโค้ดได้ง่ายขึ้น
อย่าใช้ขั้นสุดท้าย
Finalizers คือวิธีที่จะทําให้กลุ่มโค้ดถูกเรียกใช้เมื่อออบเจ็กต์ ที่มีการเก็บขยะ ส่วนขั้นสุดท้ายก็อาจมีประโยชน์สำหรับการล้างข้อมูล (โดยเฉพาะแหล่งข้อมูลภายนอก) จึงไม่มีการรับประกันว่า ผู้ขั้นสุดท้ายจะมีชื่อ (หรือแม้แต่จะต้องเรียกชื่อนั้นเลย)
Android ไม่ได้ใช้ขั้นสุดท้าย ในกรณีส่วนใหญ่ คุณสามารถใช้
การจัดการข้อยกเว้นที่ดีแทน หากคุณต้องการขั้นสุดท้ายจริงๆ
กำหนดเมธอด close()
(หรือที่คล้ายกัน) และบันทึกเมื่อ
(โปรดดู
InputStream) ในกรณีนี้
เหมาะสมแต่ไม่จำเป็นต้องพิมพ์ข้อความบันทึกสั้นๆ จาก
ผู้ขั้นสุดท้าย ตราบใดที่ไม่คาดว่าจะมีพื้นที่ท่วมบันทึก
การนําเข้าที่เข้าเกณฑ์โดยสมบูรณ์
เมื่อต้องการใช้คลาส Bar
จากแพ็กเกจ foo
จะมี
วิธีที่เป็นไปได้ในการนำเข้าข้อมูล
import foo.*;
อาจลดจำนวนข้อความการนำเข้าได้
import foo.Bar;
ทำให้เห็นได้อย่างชัดเจนว่าระบบใช้คลาสใดและโค้ดมีมากกว่า ผู้บำรุงรักษาสามารถอ่านได้
ใช้ import foo.Bar;
เพื่อนำเข้าโค้ด Android ทั้งหมด CANNOT TRANSLATE
มีการสร้างข้อยกเว้นอย่างชัดแจ้งสำหรับไลบรารีมาตรฐานของ Java (java.util.*
java.io.*
เป็นต้น) และรหัสการทดสอบหน่วย (junit.framework.*
)
กฎไลบรารี Java
มีกฎเกณฑ์ในการใช้ไลบรารีและเครื่องมือ Java ของ Android อยู่ ใน ในบางกรณี การประชุมได้มีการเปลี่ยนแปลงไปในทางที่สำคัญและโค้ดที่เก่ากว่า อาจใช้รูปแบบหรือไลบรารีที่เลิกใช้งานแล้ว เมื่อทำงานกับโค้ดดังกล่าว ก็ใช้สไตล์เดิมที่มีอยู่ต่อไป เมื่อสร้างคอมโพเนนต์ใหม่ อย่างไรก็ตาม อย่าใช้ไลบรารีที่เลิกใช้งานแล้ว
กฎรูปแบบ Java
ใช้ความคิดเห็นมาตรฐานของ Javadoc
ทุกไฟล์ควรมีข้อความลิขสิทธิ์ที่ด้านบน ตามด้วย คำสั่งแพ็กเกจและการนำเข้า (แต่ละบล็อกคั่นด้วยบรรทัดว่าง) และ สุดท้ายคือการประกาศคลาสหรืออินเทอร์เฟซ ในความคิดเห็น Javadoc อธิบายสิ่งที่ชั้นเรียนหรืออินเทอร์เฟซทำ
/* * Copyright yyyy 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 { ... }
ทุกชั้นเรียนและวิธีการแบบสาธารณะที่ไม่สำคัญที่คุณเขียนต้องมี ความคิดเห็น Javadoc ที่มีอย่างน้อย 1 ประโยคที่อธิบายสิ่งที่ชั้นเรียน หรือวิธีการดังกล่าว ประโยคนี้ควรเริ่มต้นด้วยบุคคลที่สาม คำกริยาอธิบาย
ตัวอย่าง
/** Returns the correctly rounded positive square root of a double value. */ static double sqrt(double a) { ... }
หรือ
/** * Constructs a new String by converting the specified array of * bytes using the platform's default character encoding. */ public String(byte[] bytes) { ... }
คุณไม่จำเป็นต้องเขียน Javadoc สำหรับเมธอด get และ set ที่ไม่สำคัญ เช่น
setFoo()
ถ้า Javadoc ทั้งหมดที่บอกว่า "ตั้งค่า Foo" ถ้า
เมธอดต้องซับซ้อนขึ้น (เช่น การบังคับใช้ข้อจำกัด
หรือมีผลข้างเคียงที่สำคัญ) คุณต้องจัดทำเอกสารประกอบ หากไม่ใช่
เห็นได้ชัดว่าคุณสมบัติ "Foo" เป็นอะไร คุณควรจัดทำเป็นเอกสารไว้
ทุกวิธีการที่คุณเขียน เผยแพร่สู่สาธารณะ หรืออื่นๆ จะได้ประโยชน์จาก Javadoc เมธอดสาธารณะเป็นส่วนหนึ่งของ API จึงต้องใช้ Javadoc แอนดรอยด์ ไม่ได้บังคับใช้รูปแบบเฉพาะสำหรับการเขียน Javadoc ความคิดเห็น แต่คุณควรทำตามคำแนะนำใน วิธีเขียนความคิดเห็นในเอกสารสำหรับเครื่องมือ Javadoc
เขียนวิธีการสั้นๆ
พยายามทำให้วิธีการมีขนาดเล็กและมีเป้าหมายชัดเจนเมื่อเป็นไปได้ เราตระหนักดีว่า ในบางครั้งจะมีความเหมาะสมด้วย ดังนั้นจึงไม่มีการจำกัดความเข้มงวดของเมธอด ถ้าวิธีการหนึ่งมีจำนวนอักขระเกิน 40 บรรทัด ลองพิจารณาว่าสามารถ ถูกแบ่งออกโดยไม่ส่งผลเสียต่อโครงสร้างของโปรแกรม
กำหนดช่องในตำแหน่งมาตรฐาน
กำหนดฟิลด์ที่ด้านบนของไฟล์หรืออยู่ก่อนส่วน ที่ใช้วิธีการเหล่านั้น
จำกัดขอบเขตของตัวแปร
จำกัดขอบเขตของตัวแปรภายในให้น้อยที่สุด ช่วงเวลานี้ จะเพิ่มความอ่านง่ายและดูแลรักษาโค้ดได้ โอกาสที่จะเกิดข้อผิดพลาด ประกาศตัวแปรแต่ละตัวในชั้นในสุด ที่ครอบคลุมการใช้ตัวแปรทั้งหมด
ประกาศตัวแปรภายใน ณ จุดที่มีการใช้ตัวแปรเป็นครั้งแรก การประกาศตัวแปรในเครื่องเกือบทั้งหมดควรมีโปรแกรมเริ่มต้น หากยังมีข้อมูลไม่เพียงพอที่จะเริ่มต้นตัวแปร เลื่อนการประกาศอย่างมีเหตุผลจนกว่าจะทำ
ยกเว้นคำสั่งลองดักจับ หากตัวแปรเริ่มต้นด้วย ค่าที่แสดงผลของเมธอดที่แสดงข้อยกเว้นที่ทำเครื่องหมายแล้วจะต้อง เริ่มต้นภายในบล็อกการลอง หากต้องใช้ค่านอก พยายามบล็อก จากนั้นจะต้องประกาศก่อนลองใช้คำสั่งบล็อก ยังไม่สามารถเริ่มต้นอย่างสมเหตุสมผล:
// 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));
อย่างไรก็ตาม คุณยังหลีกเลี่ยงเคสนี้ได้ด้วยการสรุปการลองดัทช์ ในเมธอด:
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));
ประกาศตัวแปรลูปในคำสั่งสำหรับตัวมันเอง ยกเว้น มีเหตุผลสมควรให้ทำอย่างอื่น เช่น
for (int i = 0; i < n; i++) { doSomething(i); }
และ
for (Iterator i = c.iterator(); i.hasNext(); ) { doSomethingElse(i.next()); }
ใบแจ้งยอดการนำเข้าคำสั่งซื้อ
ลำดับของใบแจ้งยอดการนำเข้ามีดังนี้
- การนำเข้าจาก Android
-
การนำเข้าจากบุคคลที่สาม (
com
,junit
,net
,org
) -
java
และjavax
เพื่อให้ตรงกับการตั้งค่า IDE ทุกประการ การนำเข้าควรเป็นดังนี้
- ตามลำดับตัวอักษรในแต่ละกลุ่ม โดยจะใช้อักษรตัวพิมพ์ใหญ่ก่อนตัวพิมพ์เล็ก ตัวอักษรพิมพ์เล็ก (เช่น Z ก่อน a)
-
คั่นด้วยบรรทัดว่างระหว่างการจัดกลุ่มหลักแต่ละกลุ่ม
(
android
,com
,junit
net
org
java
javax
)
ตอนแรกไม่มีข้อกำหนดด้านรูปแบบในการสั่งซื้อ ซึ่งหมายความว่าไม่มี IDE เปลี่ยนแปลงการจัดลำดับอยู่เสมอ หรือนักพัฒนา IDE ต้อง ปิดใช้ฟีเจอร์การจัดการการนำเข้าอัตโนมัติและดูแลรักษาด้วยตนเอง การนำเข้า การกระทำนี้ถือว่าแย่ เมื่อมีการถามแบบ Java สไตล์ที่ต้องการนั้นมีความหลากหลายอย่างมาก และ Android ต้อง เพียง "เลือกคำสั่งซื้อและทำให้สม่ำเสมอ" เราเลยเลือกสไตล์ อัปเดตคู่มือสไตล์ และทำให้ IDE เป็นไปตามคำสั่ง เราคาดว่า ผู้ใช้ IDE กำลังทำงานกับโค้ด การนำเข้าในแพ็กเกจทั้งหมดจะตรงกับค่านี้ โดยไม่ต้องมีความพยายามด้านวิศวกรรมเพิ่มเติม
เราเลือกรูปแบบนี้:
-
การนําเข้าที่ผู้ใช้ต้องการดูเป็นอันดับแรกมีแนวโน้มที่จะอยู่ในลำดับต้น
(
android
) -
การนำเข้าที่ผู้ใช้ต้องการดูอย่างน้อยมักจะอยู่ด้านล่าง
(
java
) - มนุษย์ทำตามสไตล์นี้ได้ง่ายๆ
- IDE สามารถใช้รูปแบบนี้ได้
วางการนำเข้าแบบคงที่เหนือการนำเข้าอื่นๆ ทั้งหมดโดยเรียงลำดับในลักษณะเดียวกับ การนำเข้าตามปกติ
ใช้การเว้นวรรคในการเยื้อง
เราใช้การเยื้องเว้นวรรคสี่ (4) สำหรับบล็อกและไม่ใช้แท็บ เมื่อไม่แน่ใจ ให้สอดคล้องกับโค้ดโดยรอบ
เราใช้การเยื้องวรรคแปด (8) สำหรับการตัดบรรทัด รวมถึงการเรียกใช้ฟังก์ชัน และงานที่มอบหมาย
แนะนำ
Instrument i = someLongExpression(that, wouldNotFit, on, one, line);
ไม่แนะนำ
Instrument i = someLongExpression(that, wouldNotFit, on, one, line);
ทำตามแบบแผนการตั้งชื่อช่อง
-
ชื่อช่องที่ไม่ใช่สาธารณะและไม่ใช่แบบคงที่จะขึ้นต้นด้วย
m
-
ชื่อช่องแบบคงที่จะขึ้นต้นด้วย
s
- ส่วนช่องอื่นๆ จะขึ้นต้นด้วยตัวอักษรพิมพ์เล็ก
-
ฟิลด์สุดท้ายแบบคงที่ (ค่าคงที่ที่จะเปลี่ยนแปลงไม่ได้) คือ
ALL_CAPS_WITH_UNDERSCORES
เช่น
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; }
ใช้รูปแบบวงเล็บปีกกามาตรฐาน
ใส่วงเล็บปีกกาในบรรทัดเดียวกับรหัส ไม่ใช่ในบรรทัดของตัวเอง:
class MyClass { int func() { if (something) { // ... } else if (somethingElse) { // ... } else { // ... } } }
เรากำหนดให้ใช้วงเล็บปีกกากับข้อความสำหรับเงื่อนไข ข้อยกเว้น: หาก เงื่อนไขทั้งหมด (เงื่อนไขและเนื้อความ) พอดีในบรรทัดเดียว อาจ (แต่ไม่จำเป็นต้อง) ใส่ทั้งหมดไว้ในบรรทัดเดียว ตัวอย่างเช่น รายการนี้ ยอมรับได้:
if (condition) { body(); }
และเป็นที่ยอมรับได้
if (condition) body();
แต่ไม่ได้รับการยอมรับ
if (condition) body(); // bad!
จำกัดความยาวของบรรทัด
ข้อความแต่ละบรรทัดในโค้ดควรมีความยาวไม่เกิน 100 อักขระ แม้ว่าจะมีการถกเถียงกันมากในกฎข้อนี้ แต่การตัดสินยังคง ความยาวสูงสุด 100 อักขระพร้อมด้วย ข้อยกเว้น:
- หากบรรทัดความคิดเห็นมีคำสั่งตัวอย่างหรือ URL แบบลิเทอรัลยาวกว่า เกิน 100 อักขระ บรรทัดนั้นอาจยาวกว่า 100 อักขระสำหรับ ตัดและวางได้ง่ายๆ
- บรรทัดที่นำเข้าอาจมีข้อความเกินขีดจำกัดเนื่องจากมนุษย์แทบไม่เห็น (ซึ่งช่วยให้การเขียนเครื่องมือง่ายขึ้น)
ใช้คำอธิบายประกอบ Java มาตรฐาน
คำอธิบายประกอบควรอยู่ก่อนตัวแก้ไขอื่นๆ สำหรับภาษาเดียวกัน
คุณสามารถแสดงคำอธิบายประกอบเครื่องหมายแบบง่าย (เช่น @Override
) ใน
บรรทัดเดียวกับองค์ประกอบภาษา หากมีคำอธิบายประกอบหลายรายการ
หรือคำอธิบายประกอบแบบพารามิเตอร์ ให้แสดงบรรทัดละ 1 รายการ
ตามลำดับตัวอักษร
แนวทางปฏิบัติมาตรฐานของ Android สำหรับคำอธิบายประกอบที่กำหนดไว้ล่วงหน้า 3 แบบใน Java ได้แก่
-
ใช้คำอธิบายประกอบ
@Deprecated
เมื่อใดก็ตามที่ไม่สนับสนุนให้ใช้เอลิเมนต์ที่มีคำอธิบายประกอบ หากคุณใช้ คำอธิบายประกอบ@Deprecated
คุณต้องมี@deprecated
แท็ก Javadoc และควรตั้งชื่อการติดตั้งใช้งานอื่น นอกจากนี้ โปรดทราบว่าเมธอด@Deprecated
ยังควรใช้งานได้ หากคุณเห็นโค้ดเก่าที่มีแท็ก Javadoc@deprecated
ให้เพิ่ม@Deprecated
-
ใช้คำอธิบายประกอบ
@Override
เมื่อใดก็ได้ เมธอดจะแทนที่การประกาศหรือการติดตั้งใช้งานจาก Superclass ตัวอย่างเช่น หากคุณใช้แท็ก Javadoc@inheritdocs
และ มาจากคลาส (ไม่ใช่อินเทอร์เฟซ) คุณจะต้องใส่คำอธิบายประกอบว่า เมธอดนั้นจะแทนที่เมธอดของคลาสระดับบนสุด -
ใช้คำอธิบายประกอบ
@SuppressWarnings
เฉพาะเมื่อ ลบคำเตือน หากคำเตือนส่งคำเตือน "ไม่สามารถ กำจัด" คำอธิบายประกอบ@SuppressWarnings
ต้องมีลักษณะดังนี้ ใช้ เพื่อให้แน่ใจว่าคำเตือนทั้งหมดแสดงถึงปัญหาจริงใน โค้ดเมื่อจำเป็นต้องใช้คำอธิบายประกอบ
@SuppressWarnings
ขึ้นต้นด้วยความคิดเห็นTODO
ที่อธิบายว่า "เป็นไปไม่ได้ที่จะ กำจัด" ซึ่งปกติแล้วเป็นการระบุถึงชั้นเรียนที่ไม่เหมาะสม ที่มีอินเทอร์เฟซที่ดูแปลกๆ เช่น// TODO: The third-party class com.third.useful.Utility.rotate() needs generics @SuppressWarnings("generic-cast") List<String> blix = Utility.rotate(blax);
เมื่อต้องใช้คำอธิบายประกอบ
@SuppressWarnings
ให้เปลี่ยนโครงสร้างภายในโค้ด เพื่อแยกองค์ประกอบของซอฟต์แวร์ที่คำอธิบายประกอบ นำไปใช้ได้
ทำให้ตัวย่อเป็นคำ
ทำให้ตัวย่อและคำย่อเป็นคำในการตั้งชื่อตัวแปร เมธอด และคลาสเพื่อให้อ่านชื่อได้ง่ายขึ้น
ดี | แย่ |
---|---|
XmlHttpRequest | คำขอ XMLHTTP |
getCustomerId | getCustomerID |
HTML คลาส | HTML ของชั้นเรียน |
URL สตริง | URL สตริง |
รหัสยาว | รหัสแบบยาว |
เนื่องจากทั้ง JDK และฐานของโค้ด Android ไม่สอดคล้องกัน ตัวย่อ แทบจะเป็นไปไม่ได้เลยที่จะตรงกับ โค้ดที่อยู่รอบๆ ดังนั้น ควรถือว่าตัวย่อเป็นคำเสมอ
ใช้ความคิดเห็นในสิ่งที่ต้องทำ
ใช้ความคิดเห็น TODO
สำหรับโค้ดที่เป็นแบบชั่วคราว วิธีแก้ปัญหาระยะสั้น หรือ
ดีพอ แต่ไม่สมบูรณ์แบบ ความคิดเห็นเหล่านี้ควรมีสตริง TODO
ในทั้งหมด
ตัวพิมพ์ใหญ่ ตามด้วยเครื่องหมายทวิภาค
// TODO: Remove this code after the UrlTable2 has been checked in.
และ
// TODO: Change this to use a flag instead of a constant.
หาก TODO
ของคุณอยู่ในรูปแบบ "ดำเนินการบางอย่างในอนาคต" ตรวจสอบว่า
ระบุวันที่ที่เจาะจง ("แก้ไขภายในเดือนพฤศจิกายน 2005") หรือ
เหตุการณ์ที่เฉพาะเจาะจง ("นำโค้ดนี้ออกหลังมิกเซอร์การผลิตทั้งหมด
เข้าใจโปรโตคอล V7")
บันทึกเท่าที่จำเป็น
แม้ว่าการบันทึกจะจำเป็น แต่ก็ส่งผลกระทบในทางลบต่อ ประสิทธิภาพการทำงานและคุณจะสูญเสียประโยชน์หากไม่ได้เก็บไว้อย่างสมเหตุสมผล จริงจัง พื้นที่การตัดไม้มีการตัดไม้ 5 ระดับดังนี้
-
ERROR
: ใช้เมื่อเกิดเหตุการณ์ร้ายแรง นั่นคือ บางอย่างจะมีผลลัพธ์ที่ผู้ใช้มองเห็นได้และไม่สามารถกู้คืนได้ โดยไม่ต้องลบข้อมูลบางอย่าง ถอนการติดตั้งแอป ล้างพาร์ติชันข้อมูลหรือรีเฟรชอุปกรณ์ทั้งเครื่อง (หรือที่แย่กว่านั้น) ระดับนี้จะได้รับการบันทึกเสมอ ปัญหาที่สนับสนุนการบันทึก ระดับERROR
เป็นตัวเลือกที่ดีที่จะรายงานไปยัง เซิร์ฟเวอร์รวบรวมข้อมูลสถิติ -
WARNING
: ใช้เมื่อมีสิ่งที่ร้ายแรงและคาดไม่ถึง กล่าวคือ บางอย่างจะมีผลลัพธ์ที่ผู้ใช้มองเห็นได้ แต่ มีแนวโน้มที่จะกู้คืนได้โดยไม่มีข้อมูลสูญหาย การดำเนินการที่ชัดเจน ตั้งแต่การรอหรือรีสตาร์ทแอปจนสุด การดาวน์โหลดแอปเวอร์ชันใหม่หรือรีบูต อุปกรณ์ ระดับนี้จะได้รับการบันทึกเสมอ ปัญหาที่ทำให้เกิดการบันทึก ที่ระดับWARNING
ก็อาจได้รับการพิจารณาสำหรับการรายงานไปยัง เซิร์ฟเวอร์รวบรวมข้อมูลสถิติ -
INFORMATIVE
: ใช้เพื่อจดบันทึกสิ่งที่น่าสนใจ กล่าวคือ เมื่อตรวจพบสถานการณ์ที่มีแนวโน้มว่าจะ สร้างผลกระทบในวงกว้าง แต่ก็ไม่ใช่ข้อผิดพลาดเสมอไป เช่น ควรบันทึกโดยโมดูลที่เชื่อว่า โดเมนเชื่อถือได้มากที่สุดในโดเมนนั้น (เพื่อหลีกเลี่ยงการซ้ำซ้อน การบันทึกโดยคอมโพเนนต์ที่ไม่ได้รับอนุญาต) ระดับนี้จะได้รับการบันทึกเสมอ -
DEBUG
: ใช้เพื่อบันทึกเพิ่มเติมว่ามีอะไรเกิดขึ้นบ้าง อุปกรณ์ที่อาจเกี่ยวข้องในการตรวจสอบและแก้ไขข้อบกพร่องที่ไม่คาดคิด พฤติกรรมของคุณ บันทึกเฉพาะสิ่งที่จำเป็นในการรวบรวมข้อมูลให้เพียงพอ ข้อมูลเกี่ยวกับสิ่งที่เกิดขึ้นกับคอมโพเนนต์ หากการแก้ไขข้อบกพร่อง บันทึกกำลังควบคุมบันทึก คุณจึงควรใช้แบบละเอียด การเข้าสู่ระบบระบบจะบันทึกระดับนี้แม้ในเวอร์ชันรุ่น และจำเป็นต้องใช้ จะถูกล้อมรอบด้วยบล็อก
if (LOCAL_LOG)
หรือif LOCAL_LOGD)
โดยที่กำหนดLOCAL_LOG[D]
ไว้ ในชั้นเรียนหรือองค์ประกอบย่อย เพื่อให้มีโอกาส เพื่อปิดใช้การบันทึกดังกล่าวทั้งหมด ดังนั้นจึงต้องไม่มีตรรกะที่ใช้งานอยู่ ในif (LOCAL_LOG)
การสร้างสตริงทั้งหมดสำหรับ บันทึกยังจะต้องวางไว้ใน บล็อกif (LOCAL_LOG)
อย่าเปลี่ยนโครงสร้างของการเรียกใช้การบันทึก ให้เป็นการเรียกใช้เมธอดหากจะทำให้เกิด ในการสร้างสตริงภายนอก บล็อกif (LOCAL_LOG)
มีรหัสบางอย่างที่ยังเขียนว่า
if (localLOGV)
ช่วงเวลานี้ ก็ถือว่ายอมรับได้เช่นกัน แม้ว่าชื่อจะไม่เป็นมาตรฐานก็ตาม -
VERBOSE
: ใช้กับสิ่งอื่นๆ ระดับนี้เท่านั้น บันทึกในบิลด์การแก้ไขข้อบกพร่องแล้ว และควรล้อมรอบด้วยif (LOCAL_LOGV)
บล็อก (หรือเทียบเท่า) เพื่อให้สามารถ ซึ่งคอมไพล์ออกมาโดยค่าเริ่มต้น การสร้างสตริงใดๆ ถูกตัดออก บิลด์ที่เผยแพร่ และจำเป็นต้องปรากฏใน บล็อกif (LOCAL_LOGV)
หมายเหตุ
-
ภายในโมดูลหนึ่งๆ เกิดข้อผิดพลาดนอกเหนือจากที่ระดับ
VERBOSE
ควรรายงานเพียงครั้งเดียวหากเป็นไปได้ ภายในเชนเดียวกัน การเรียกฟังก์ชันภายในโมดูล เฉพาะฟังก์ชันชั้นในสุดเท่านั้นที่ควร แสดงข้อผิดพลาด และผู้โทรในโมดูลเดียวกันควรเพิ่ม ให้บันทึกหากวิธีนี้ช่วยแยกปัญหาได้อย่างมาก -
ในเชนโมดูล นอกเหนือจากที่ระดับ
VERBOSE
เมื่อ โมดูลระดับต่ำลงมาตรวจพบว่าข้อมูลที่ไม่ถูกต้องมาจากระดับที่สูงกว่า โมดูลระดับล่างควรบันทึกสถานการณ์นี้ลงใน บันทึกDEBUG
และเฉพาะในกรณีที่การบันทึกให้ข้อมูลที่ไม่ใช่ ไม่พร้อมให้บริการสำหรับผู้โทร โดยเฉพาะอย่างยิ่ง คุณไม่จำเป็นต้อง บันทึกที่มีข้อยกเว้น (ข้อยกเว้นควร มีข้อมูลที่เกี่ยวข้องทั้งหมด) หรือที่มีเฉพาะข้อมูล ที่ถูกบันทึกอยู่ในรหัสข้อผิดพลาด โดยเฉพาะอย่างยิ่ง สำคัญในการโต้ตอบระหว่างเฟรมเวิร์กกับแอป ที่เกิดจากแอปของบุคคลที่สาม ที่มีการจัดการโดยเฟรมเวิร์กไม่ควรทำให้การบันทึกสูงกว่า ระดับDEBUG
สถานการณ์เดียวที่ควรทริกเกอร์การบันทึกที่ ระดับINFORMATIVE
ขึ้นไปคือระดับเมื่อโมดูลหรือแอปตรวจพบ ข้อผิดพลาดในระดับนั้นเองหรือมาจากระดับที่ต่ำกว่า - เมื่อเงื่อนไขที่โดยปกติแล้วควรอธิบายเหตุผลของการบันทึก เกิดขึ้นหลายครั้ง เป็นความคิดที่ดีที่จะใช้ เพื่อป้องกันไม่ให้ไฟล์บันทึกล้นเกิน สำเนาของข้อมูลที่เหมือน (หรือคล้ายกันมาก) ซ้ำ
-
การสูญเสียการเชื่อมต่อเครือข่ายถือเป็นเรื่องที่พบได้บ่อยและเต็มรูปแบบ
และไม่ควรบันทึกโดยไม่มีเหตุอันควร การสูญเสียเครือข่าย
การเชื่อมต่อที่มีผลภายในแอปควรได้รับการบันทึกที่
ระดับ
DEBUG
หรือVERBOSE
(ขึ้นอยู่กับว่า ร้ายแรงเพียงพอและคาดไม่ถึงพอที่จะบันทึกไว้ในการเผยแพร่ เริ่มต้น) - มีระบบไฟล์ที่สมบูรณ์ในระบบไฟล์ที่เข้าถึงได้หรือ ในนามของแอปของบุคคลที่สามไม่ควรบันทึกในระดับ สูงกว่า INFORMATIVE
-
ข้อมูลที่ไม่ถูกต้องซึ่งมาจากแหล่งที่มาที่ไม่น่าเชื่อถือ (รวมถึงไฟล์ที่อยู่ใน
พื้นที่เก็บข้อมูลที่ใช้ร่วมกัน หรือข้อมูลที่มาจากเครือข่าย
การเชื่อมต่อ) ถือว่าเป็นการดำเนินการที่คาดไว้และไม่ควรทำให้เกิดการทริกเกอร์ใดๆ
บันทึกในระดับที่สูงกว่า
DEBUG
เมื่อตรวจพบว่าเป็น ไม่ถูกต้อง (นอกจากนี้ การบันทึกควรมีการ จำกัด น้อยที่สุดเท่าที่จะเป็นไปได้) -
เมื่อใช้กับออบเจ็กต์
String
โอเปอเรเตอร์+
โดยปริยาย สร้างอินสแตนซ์StringBuilder
ที่มีค่าเริ่มต้น ขนาดบัฟเฟอร์ (16 อักขระ) และString
ชั่วคราวอื่นๆ ออบเจ็กต์ ดังนั้นการสร้างออบเจ็กต์StringBuilder
อย่างชัดเจนจึงไม่มากกว่า ราคาแพงกว่าการใช้โอเปอเรเตอร์+
เริ่มต้น (และอาจ ที่มีประสิทธิภาพมากขึ้น) โปรดทราบว่ารหัสที่เรียกใช้Log.v()
ได้รับการคอมไพล์และดำเนินการในบิลด์รุ่นแล้ว ซึ่งรวมถึงการสร้างสตริง แม้ว่าจะไม่มีการอ่านบันทึกก็ตาม -
การบันทึกใดๆ ที่มีเจตนาให้บุคคลอื่นอ่าน และ
ที่มีอยู่ในบิลด์การเผยแพร่ควรไม่ละเอียดเพียงพอ
และควรเข้าใจได้ ซึ่งรวมถึงการบันทึกทั้งหมด
สูงสุดถึงระดับ
DEBUG
- หากเป็นไปได้ ให้เข้าสู่ระบบในบรรทัดเดียวต่อไป บรรทัดมีความยาวไม่เกิน 80 หรือ 100 อักขระ ที่ยอมรับได้ หลีกเลี่ยงความยาวที่ยาวเกิน 130 หรือ 160 อักขระโดยประมาณ (รวมถึงความยาวของแท็ก) หากเป็นไปได้
-
หากการบันทึกรายงานสำเร็จ อย่าใช้ในระดับที่สูงกว่า
VERBOSE
-
หากคุณใช้การบันทึกชั่วคราวเพื่อวิเคราะห์ปัญหาที่ดำเนินการได้ยาก
ทำซ้ำโดยเก็บไว้ที่ระดับ
DEBUG
หรือVERBOSE
และ ล้อมรอบด้วยถ้าบล็อกที่สามารถปิดใช้งานได้ เวลาคอมไพล์ - โปรดระวังการรั่วไหลด้านความปลอดภัยผ่านบันทึก หลีกเลี่ยงการบันทึกแบบส่วนตัว โดยเฉพาะอย่างยิ่ง ให้หลีกเลี่ยงการบันทึกข้อมูลเกี่ยวกับเนื้อหาที่ได้รับการคุ้มครอง ซึ่งสำคัญมากเมื่อ การเขียนโค้ดเฟรมเวิร์ก เพราะการที่จะรู้ล่วงหน้าว่า และไม่ใช่ข้อมูลส่วนตัว หรือเนื้อหาที่ได้รับการคุ้มครอง
-
ไม่ใช้
System.out.println()
(หรือprintf()
สำหรับ โค้ดแบบเนทีฟ)System.out
และSystem.err
จะได้รับ เปลี่ยนเส้นทางไปยัง/dev/null
ดังนั้นใบแจ้งยอดการพิมพ์ของคุณไม่มี ที่มองเห็นได้ อย่างไรก็ตาม การสร้างสตริงทั้งหมดที่เกิดขึ้น การเรียกใช้เหล่านี้จะยังคงเกิดขึ้น - กฎเหล็กของการบันทึกการใช้งานคือการบันทึกของคุณจะต้องไม่ พุชไฟล์บันทึกอื่นออกจากบัฟเฟอร์โดยไม่จำเป็น เช่นเดียวกับที่ผู้อื่นอาจ อย่ายัดเยียดผลงานของคุณ
กฎรูปแบบ Javatests
ทำตามแบบแผนการตั้งชื่อวิธีการทดสอบและใช้เครื่องหมายขีดล่างเพื่อแยก สิ่งที่ทดสอบจากเคสที่เฉพาะเจาะจงที่กำลังทดสอบ สไตล์นี้ช่วยให้ เพื่อดูว่ากรณีใดได้รับการทดสอบอยู่ได้ง่ายขึ้น เช่น
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)) }