การใช้ตัวปรับแต่ง“ final” เมื่อใดก็ตามที่เกี่ยวข้องใน Java [ปิด]


194

ใน Java มีการประกาศตัวแปรทุกตัว (ในตัวเครื่องหรือคลาส) พารามิเตอร์สุดท้ายถ้าเป็นจริง

แม้ว่าจะทำให้รหัส verbose มากขึ้นนี้ช่วยในการอ่าน / จับรหัสได้ง่ายและยังป้องกันข้อผิดพลาดตามที่ตั้งใจไว้ชัดเจน

คุณคิดอย่างไรกับเรื่องนี้และคุณติดตามอะไร


13
สิ่งนี้สามารถนำไปสู่การโต้แย้งทางศาสนา บางคนชอบมันบางคนเกลียดมัน ฉันชอบฟิลด์สุดท้าย แต่ไม่ใช่ตัวแปรท้องถิ่นขั้นสุดท้ายเว้นแต่พวกเขาจำเป็นต้องเป็นไม่แน่ใจว่ามันมีเหตุผลทั้งหมด ไม่แน่ใจว่าจะมีการลงคะแนนใด ๆ ฉันเห็นด้วยกับ Alex Miller ;)
Peter Lawrey

ฉันสามารถเข้าใจได้ถ้าคนไม่ชอบมีรหัสของพวกเขายุ่งเหยิงกับรอบชิงชนะเลิศ แต่นี่เป็นปัญหาที่ผู้แก้ไขที่ดีสามารถแก้ไขได้: bugs.eclipse.org/bugs/show_bug.cgi?id=409379
oberlies

คำตอบ:


184

ฉันคิดว่าทุกอย่างเกี่ยวข้องกับรูปแบบการเข้ารหัสที่ดี แน่นอนว่าคุณสามารถเขียนโปรแกรมที่ดีและมีประสิทธิภาพได้โดยไม่ต้องใช้finalตัวดัดแปลงจำนวนมากที่ไหนก็ได้ แต่เมื่อคุณคิดถึงมัน ...

การเพิ่มfinalทุกสิ่งที่ไม่ควรเปลี่ยนให้แคบลงความเป็นไปได้ที่คุณ (หรือโปรแกรมเมอร์คนต่อไปที่ทำงานกับโค้ดของคุณ) จะตีความหรือใช้กระบวนการคิดที่ผิดซึ่งทำให้รหัสของคุณผิด อย่างน้อยก็ควรส่งเสียงระฆังเมื่อพวกเขาต้องการเปลี่ยนสิ่งที่ไม่เปลี่ยนรูปก่อนหน้านี้ของคุณ

ในตอนแรกมันดูค่อนข้างอึดอัดที่จะเห็นfinalคำหลักจำนวนมากในรหัสของคุณ แต่ในไม่ช้าคุณจะสังเกตเห็นคำศัพท์นั้นและจะคิดว่าสิ่งที่จะไม่เปลี่ยนแปลงจากจุดนี้ บน (คุณสามารถรับมันได้จากฉัน ;-)

ฉันคิดว่ามันเป็นวิธีปฏิบัติที่ดี ฉันไม่ได้ใช้มันตลอดเวลา แต่เมื่อใดที่ฉันสามารถทำได้finalฉันจะทำ


16
แทนที่จะใช้คำหลักสุดท้ายสำหรับพารามิเตอร์คุณสามารถใช้เครื่องมือวิเคราะห์แบบคงที่เช่น FindBugs เพื่อกำหนดว่าตัวแปรพารามิเตอร์จะไม่ถูกกำหนดใหม่ วิธีนี้คุณจะลบภาระวากยสัมพันธ์และสามารถบังคับใช้ผ่านเช็ค FindBugs ในเครื่องมือการรวมอย่างต่อเนื่องของคุณ
Timo Westkämper

20
@Timo นี้จะใช้งานได้ แต่มีข้อเสียที่ต้องตรวจสอบหลังจากเช็คอินและไม่ได้ในขณะที่ dev กำลังทำงานกับรหัส สำหรับfinalคอมไพเลอร์จะไม่ยอมให้คุณทำต่อไปถ้าคุณทำผิด
Mike

9
Eclipse มีตัวเลือกในการเพิ่มเมื่อfinalใดก็ตามที่เป็นไปได้ (ตัวแปรที่ไม่เปลี่ยนแปลง) ทุกครั้งที่คุณบันทึก
Bert F

22
+1 finalผมรัก มันไม่ได้สร้างความแตกต่าง 98% ของเวลามันเป็นความไม่สะดวกเล็ก ๆ น้อย ๆ % 1 ของเวลา แต่ 1% ของเวลานั้นช่วยฉันจากการทำอะไรที่โง่หรือไม่ตั้งใจมันคุ้มค่ามาก
Bert F

14
@BertF ใช่ฉันมักจะปล่อยให้ Eclipse เพิ่มfinalตัวดัดแปลงทุกที่เมื่อฉัน "ล้าง ... " รหัสของฉัน ทุกที่หมายถึงแม้จะอยู่ในช่วง catch () บล็อกและตามที่กล่าวไว้คุณจะไม่สังเกตเห็นหลังจากผ่านไประยะหนึ่ง แน่นอนถ้าฉันจะสร้างภาษาสิ่งfinalนั้นจะเป็นค่าเริ่มต้นและ a varหรือmodifiableจะเป็นคำหลักเพิ่มเติม
Maarten Bodewes

191

ครอบงำมากกว่า:

  • Final fields - การทำเครื่องหมายฟิลด์เป็นขั้นสุดท้ายบังคับให้ตั้งค่าให้เสร็จสิ้นการก่อสร้างทำให้การอ้างอิงฟิลด์นั้นไม่เปลี่ยนรูป วิธีนี้ช่วยให้สามารถเผยแพร่ฟิลด์ได้อย่างปลอดภัยและสามารถหลีกเลี่ยงความจำเป็นในการซิงโครไนซ์ในภายหลังได้ (โปรดทราบว่าสำหรับการอ้างอิงวัตถุเฉพาะการอ้างอิงฟิลด์นั้นไม่สามารถเปลี่ยนแปลงได้ - สิ่งที่การอ้างอิงวัตถุหมายถึงยังคงสามารถเปลี่ยนแปลงได้และมีผลต่อการเปลี่ยนแปลงไม่ได้)
  • เขตข้อมูลคงที่สุดท้าย - แม้ว่าฉันจะใช้ enums ตอนนี้สำหรับหลาย ๆ กรณีที่ฉันเคยใช้เขตข้อมูลสุดท้ายคงที่

พิจารณา แต่ใช้อย่างรอบคอบ:

  • คลาสสุดท้าย - การออกแบบ Framework / API เป็นกรณีเดียวที่ฉันพิจารณา
  • วิธีสุดท้าย - โดยทั่วไปเหมือนกับชั้นเรียนสุดท้าย หากคุณใช้รูปแบบวิธีการของแม่แบบอย่างบ้าคลั่งและทำเครื่องหมายสิ่งสุดท้ายคุณอาจต้องพึ่งพาการสืบทอดมากเกินไปและไม่เพียงพอในการมอบหมาย

ไม่สนใจยกเว้นความรู้สึกทางทวารหนัก:

  • พารามิเตอร์ของเมธอดและตัวแปรโลคัล - ฉันไม่ค่อยทำสิ่งนี้เป็นส่วนใหญ่เพราะฉันขี้เกียจและฉันพบว่ามันเป็นกลุ่มของรหัส ฉันจะยอมรับอย่างเต็มที่ว่าการทำเครื่องหมายพารามิเตอร์และตัวแปรท้องถิ่นที่ฉันจะไม่แก้ไขคือ "righter" ฉันหวังว่ามันจะเป็นค่าเริ่มต้น แต่มันก็ไม่ได้และฉันพบว่ารหัสยากขึ้นที่จะเข้าใจกับรอบชิงชนะเลิศ ถ้าฉันอยู่ในรหัสของคนอื่นฉันจะไม่ดึงมันออกมา แต่ถ้าฉันเขียนรหัสใหม่ฉันจะไม่ใส่เข้าไปในข้อยกเว้นหนึ่งข้อคือกรณีที่คุณต้องทำเครื่องหมายสิ่งสุดท้ายเพื่อให้คุณสามารถเข้าถึงได้ จากภายในชั้นในที่ไม่ระบุชื่อ

8
คำตอบที่ดีที่สุดในหลายคำถามในหัวข้อสุดท้ายนี้
Gabriel Ščerbák

4
ส่วนใหญ่เวลาที่ฉันเห็นตัวแปรโลคอลโดยไม่มีคำสุดท้ายอยู่ข้างหน้าและไม่สามารถใช้งานได้มันบอกฉันว่าฉันน่าจะดึงโค้ดบางอย่างในวิธีการใหม่ที่คืนค่าที่ต้องการที่ฉันจะทำให้สุดท้าย กรณีที่สิ่งนี้ไม่สามารถใช้ได้คือเมื่อฉันใช้กระแสข้อมูลบางส่วนหรืออื่น ๆ ที่ต้องมีการลองใช้
nyxz

32

คุณต้องเข้าใจการใช้คำหลักสุดท้ายอย่างสมบูรณ์ก่อนที่จะใช้ มันสามารถนำไปใช้และมีผลกระทบแตกต่างกันไปในตัวแปรฟิลด์วิธีการและชั้นเรียน

ฉันขอแนะนำให้ตรวจสอบบทความที่ลิงก์ด้านล่างเพื่อดูรายละเอียดเพิ่มเติม

คำสุดท้ายในคำหลักสุดท้าย


29

โมดิfinalฟายเออร์โดยเฉพาะอย่างยิ่งสำหรับตัวแปรเป็นวิธีการที่คอมไพเลอร์บังคับใช้การประชุมที่มีเหตุผลโดยทั่วไป: ตรวจสอบให้แน่ใจว่าตัวแปร (ในตัวเครื่องหรืออินสแตนซ์) ถูกกำหนดอย่างแน่นอนหนึ่งครั้ง (ไม่มากไม่น้อย) ด้วยการทำให้แน่ใจว่าตัวแปรถูกกำหนดอย่างแน่นอนก่อนที่จะใช้คุณสามารถหลีกเลี่ยงกรณีทั่วไปของNullPointerException:

final FileInputStream in;
if(test)
  in = new FileInputStream("foo.txt");
else
  System.out.println("test failed");
in.read(); // Compiler error because variable 'in' might be unassigned

โดยการป้องกันไม่ให้ตัวแปรกำหนดมากกว่าหนึ่งครั้งคุณจะไม่สนับสนุนการกำหนดขอบเขต overbroad แทนสิ่งนี้:

 String msg = null;
 for(int i = 0; i < 10; i++) {
     msg = "We are at position " + i;
     System.out.println(msg);
 }
 msg = null;

คุณควรใช้สิ่งนี้:

 for(int i = 0; i < 10; i++) {
     final String msg = "We are at position " + i;
     System.out.println(msg);
 }

ลิงค์บางส่วน:


1
+1 สำหรับการโต้แย้งการกำหนดขอบเขตข้ามถนน
Tom Tresansky

ในระยะสั้นที่คุณสามารถโดยทั่วไปคุณสามารถใช้finalเพื่อทำให้ Java แสดงออกมากขึ้นตาม
Adam Gent

ที่จริง "โดยการทำให้แน่ใจว่าตัวแปรถูกกำหนดอย่างแน่นอนก่อนที่จะใช้คุณสามารถหลีกเลี่ยงกรณีทั่วไปของ NullPointerException:" นี่ไม่ถูกต้อง 'ขั้นสุดท้าย' สร้างความแตกต่างไม่ได้ที่นี่คอมไพเลอร์รู้และบ่นเกี่ยวกับตัวแปร 'ใน' เป็นโมฆะในตัวอย่างที่ให้ไว้
nyholku

@nyholku คุณถูกต้องใน Java ตัวแปรท้องถิ่นจะต้องได้รับมอบหมายอย่างแน่นอนก่อนการใช้งานโดยไม่ต้องสุดท้าย แต่สำหรับสาขาที่คุณต้องการขั้นสุดท้าย ในตัวอย่างที่ซับซ้อนกว่าเล็กน้อยโดยที่ "in" เป็นตัวแปรอินสแตนซ์ของคลาสและหาก / else อยู่ใน Constructor คุณต้องมีขั้นตอนสุดท้ายเพื่อส่งสัญญาณปัญหา นอกจากนี้สำหรับตัวแปรท้องถิ่นยังมีค่าบางค่าใน IMO สุดท้ายเนื่องจากจะป้องกันโปรแกรมเมอร์เลอะเทอะจาก 'แก้ไข' ข้อผิดพลาดในการคอมไพล์เกี่ยวกับ "ใน" อาจไม่ได้กำหนดโดยการเพิ่ม "= null" ลงในการประกาศ กล่าวอีกนัยหนึ่งตัวแปรสุดท้ายลดการใช้ null ในประสบการณ์ของฉัน
Bruno De Fraine

20

ฉันค่อนข้างดื้อรั้นเกี่ยวกับการประกาศตัวแปรที่เป็นไปได้finalทั้งหมด ซึ่งรวมถึงพารามิเตอร์วิธีตัวแปรท้องถิ่นและไม่ค่อยฟิลด์วัตถุค่า ฉันมีสามเหตุผลหลักในการประกาศตัวแปรสุดท้ายทุกที่:

  1. การประกาศเจตนา: ด้วยการประกาศตัวแปรขั้นสุดท้ายฉันกำลังระบุว่าตัวแปรนี้ถูกเขียนขึ้นเพียงครั้งเดียว มันเป็นคำใบ้ที่ละเอียดอ่อนสำหรับนักพัฒนาคนอื่น ๆ และเป็นคำใบ้ขนาดใหญ่สำหรับคอมไพเลอร์
  2. การบังคับใช้ตัวแปรแบบใช้ครั้งเดียว: ฉันเชื่อในความคิดที่ว่าตัวแปรแต่ละตัวควรมีจุดประสงค์เดียวในชีวิต โดยการให้แต่ละตัวแปรมีวัตถุประสงค์เดียวเท่านั้นคุณจะลดเวลาที่ใช้ในการค้นหาวัตถุประสงค์ของตัวแปรนั้นในขณะทำการดีบั๊ก
  3. ช่วยให้การเพิ่มประสิทธิภาพ: ฉันรู้ว่าคอมไพเลอร์เคยมีเทคนิคการเพิ่มประสิทธิภาพซึ่งอาศัยเฉพาะในการเปลี่ยนแปลงตัวแปรที่อ้างอิงไม่ได้ ฉันชอบคิดว่าเทคนิคเก่า ๆ เหล่านี้ (หรืออันใหม่) จะถูกใช้โดยคอมไพเลอร์

อย่างไรก็ตามฉันคิดว่าคลาสและวิธีการขั้นสุดท้ายนั้นแทบจะไม่เป็นประโยชน์เท่ากับการอ้างอิงตัวแปรขั้นสุดท้าย finalคำหลักเมื่อใช้กับการประกาศเหล่านี้ก็ให้อุปสรรคในการทดสอบแบบอัตโนมัติและการใช้รหัสของคุณในรูปแบบที่คุณอาจไม่เคยคาดการณ์ไว้


2
finalตัวแปรและพารามิเตอร์เมธอดไม่มีผลกระทบต่อประสิทธิภาพเนื่องจากไม่ได้แสดงในไบต์
Steve Kuo

ตัวแปร: = latin: varius> หลากหลาย> แก้ไขได้
dieter

17

Effective Java มีรายการที่ระบุว่า "โปรดปรานวัตถุที่ไม่เปลี่ยนรูปแบบ" การประกาศฟิลด์เป็นขั้นตอนสุดท้ายจะช่วยให้คุณทำตามขั้นตอนเล็ก ๆ ได้ แต่แน่นอนว่ายังมีอีกมากสำหรับวัตถุที่ไม่เปลี่ยนรูปจริง ๆ

ถ้าคุณรู้ว่าอ็อบเจกต์ไม่สามารถเปลี่ยนแปลงได้พวกเขาสามารถแชร์เพื่ออ่านในหลาย ๆ เธรด / ไคลเอนต์โดยไม่ต้องกังวลเรื่องการซิงโครไนซ์และมันง่ายกว่าที่จะให้เหตุผลว่าโปรแกรมรันอย่างไร


15
ระวัง - สุดท้ายและไม่เปลี่ยนรูปเป็นแนวคิดที่แตกต่างอย่างสิ้นเชิง มันง่ายที่จะมีวัตถุที่เปลี่ยนแปลงได้สุดท้าย - สุดท้ายคือเกี่ยวกับการอ้างอิงความไม่แน่นอนเป็นเรื่องเกี่ยวกับวัตถุตัวอย่าง คนสุดท้าย olaf = คนใหม่ (); olaf.setName ( "โอลาฟ");
Olaf Kock

1
แน่นอน - วัตถุที่ไม่เปลี่ยนรูปเป็นสิ่งหนึ่งการอ้างอิงที่ไม่เปลี่ยนรูป (เช่นสุดท้าย) เป็นอย่างอื่นทั้งหมด
SCdF

2
แต่พวกเขามีความสัมพันธ์กันอย่างใกล้ชิดเนื่องจากคุณสามารถทำได้โดยการประกาศฟิลด์ Person.name เป็นขั้นสุดท้าย (และการประกาศคลาสสุดท้ายและ ... ) ทำให้อ็อบเจกต์ Person เป็นที่สิ้นสุด อย่างไรก็ตามมันไม่ใช่เรื่องง่ายเหมือนแค่ทำ "คนสุดท้าย" ...
เซบาสเตียน Ganslandt

สิ่งนี้ไม่เกี่ยวข้องกับตัวแปรโลคัล (พารามิเตอร์คือ locals) มันใช้กับตัวแปรคลาสเท่านั้นดังนั้นมันจึงตอบคำถามได้เพียงบางส่วนเท่านั้น
Robin

12

ฉันไม่เคยอยู่ในสถานการณ์ที่มีคำหลักสุดท้ายในตัวแปรทำให้ฉันไม่สามารถทำผิดพลาดได้ดังนั้นในขณะที่ฉันคิดว่ามันเป็นเรื่องใหญ่เสียเวลา

เว้นแต่จะมีเหตุผลที่แท้จริงสำหรับการทำมัน (เช่นเดียวกับที่คุณต้องการให้จุดเฉพาะเกี่ยวกับตัวแปรที่เป็นครั้งสุดท้าย) ฉันจะไม่ทำเพราะฉันพบว่ามันทำให้รหัสอ่านน้อย

อย่างไรก็ตามหากคุณไม่พบว่ามันทำให้การอ่านยากขึ้นหรือการเขียนนานกว่านั้นไม่ว่าจะด้วยวิธีใดก็ตาม

แก้ไข:เพื่อความกระจ่าง (และความพยายามที่จะชนะคะแนนโหวต) ฉันไม่ได้บอกว่าอย่าทำเครื่องหมายว่าค่าคงที่เป็นขั้นสุดท้ายฉันกำลังพูดว่าไม่ได้ทำสิ่งที่ชอบ:

public String doSomething() {
  final String first = someReallyComplicatedExpressionToGetTheString();
  final String second = anotherReallyComplicatedExpressionToGetAnother();

  return first+second;
}

มันทำให้อ่านยาก (ในความคิดของฉัน)

มันก็คุ้มค่าที่จะจำได้ว่าสิ่งสุดท้ายที่ทำคือป้องกันคุณจากการกำหนดตัวแปรอีกครั้งมันไม่ทำให้ไม่เปลี่ยนรูปหรืออะไรทำนองนั้น


1
การเปลี่ยนคำพูดบนหัว: ฉันได้รับในสถานการณ์มากมายที่ไม่ได้ใช้final(และวัตถุที่ไม่เปลี่ยนรูปแบบโดยทั่วไป) มีปัจจัยสนับสนุนที่สำคัญต่อจำนวนและผลกระทบของข้อบกพร่อง
คริส Vest

3
ฉันทั้งหมดสำหรับวัตถุที่ไม่เปลี่ยนรูปฉันไม่เคยอยู่ในสถานการณ์ที่การทำเครื่องหมายวัตถุที่ไม่เปลี่ยนรูปสุดท้ายช่วยให้ฉันได้
SCdF

2
ฉันยอมรับว่าเราไม่ควรใช้ขั้นสุดท้ายกับตัวแปรโลคัลและพารามิเตอร์เมธอดมันทำให้โค้ดอ่านน้อยลงมาก
rmaruszewski

@ChrisVest บางทีฟังก์ชั่นของคุณอาจยาวเกินไป
Pacerier

8

ขั้นสุดท้ายควรใช้สำหรับค่าคงที่เสมอ มันมีประโยชน์สำหรับตัวแปรอายุสั้น (ภายในวิธีเดียว) เมื่อกฎสำหรับการกำหนดตัวแปรนั้นซับซ้อน

ตัวอย่างเช่น:

final int foo;
if (a)
    foo = 1;
else if (b)
    foo = 2;
else if (c)
    foo = 3;
if (d)        // Compile error:  forgot the 'else'
    foo = 4;
else
    foo = -1;

6

ดูเหมือนจะเป็นหนึ่งในอาร์กิวเมนต์ที่ใหญ่ที่สุดเมื่อเทียบกับการใช้คำหลักสุดท้ายคือ "มันไม่จำเป็น" และ "เสียพื้นที่"

หากเรายอมรับประโยชน์มากมายของ "ขั้นตอนสุดท้าย" ตามที่โพสต์ยอดเยี่ยมจำนวนมากที่นี่ในขณะที่ยอมรับว่าใช้การพิมพ์และพื้นที่มากขึ้นฉันจะยืนยันว่า Java ควรทำให้ตัวแปร "สุดท้าย" เป็นค่าเริ่มต้นและต้องการให้มีการทำเครื่องหมาย " ไม่แน่นอน "ถ้า coder ต้องการให้มันเป็น


1
Downvoters อยากอธิบายไหม?
RAY

ดูเหมือนจะแปลกที่จะเรียกมันว่าตัวแปรแล้วใช่ไหม?
อลัน

2
มีคำศัพท์ภาษาอังกฤษให้เลือกมากมาย
RAY

มันสมบูรณ์แบบ ไม่มีข้อโต้แย้งfinalนอกเหนือจาก "นานเกินไปที่จะเขียน", "ทำให้รหัส clumsier" finalมีข้อโต้แย้งหลายประการสำหรับการเป็น และเราสามารถเพิ่มลงในบันทึกโดยอัตโนมัติหากคุณไม่ต้องการพิมพ์ด้วยมือ
Dmitriy Popov

5

ฉันใช้finalตลอดเวลาสำหรับคุณลักษณะของวัตถุ

finalคำหลักที่มีความหมายการแสดงผลเมื่อใช้กับแอตทริบิวต์วัตถุ โดยพื้นฐานแล้วการตั้งค่าของแอตทริบิวต์ของวัตถุสุดท้ายเกิดขึ้นก่อนที่ Constructor จะคืนค่า ซึ่งหมายความว่าตราบใดที่คุณไม่ปล่อยให้การthisอ้างอิงหนีตัวสร้างและคุณใช้finalสำหรับทุกคนคุณลักษณะของคุณวัตถุของคุณคือ (ภายใต้ความหมาย Java 5 ความหมาย) รับประกันว่าจะสร้างอย่างถูกต้องและเนื่องจากยังไม่เปลี่ยนรูปมันจึงสามารถเผยแพร่ได้อย่างปลอดภัย ไปยังหัวข้ออื่น ๆ

วัตถุที่ไม่เปลี่ยนรูปนั้นไม่ได้เกี่ยวกับความปลอดภัยของเธรดเท่านั้น นอกจากนี้ยังทำให้ง่ายขึ้นมากในการให้เหตุผลเกี่ยวกับการเปลี่ยนสถานะในโปรแกรมของคุณเนื่องจากพื้นที่ของสิ่งที่สามารถเปลี่ยนแปลงนั้นมีเจตนาและหากใช้อย่างสม่ำเสมอให้ จำกัด เฉพาะสิ่งที่ควรเปลี่ยนเท่านั้น

บางครั้งฉันก็ทำให้วิธีการสุดท้าย แต่ไม่บ่อย ฉันเรียนเป็นครั้งสุดท้ายไม่บ่อยนัก โดยทั่วไปฉันทำสิ่งนี้เพราะฉันมีความต้องการน้อย โดยทั่วไปฉันไม่ได้ใช้มรดกมากนัก ฉันชอบที่จะใช้อินเทอร์เฟซและการจัดวางวัตถุแทน - นี่ยังให้ตัวเองกับการออกแบบที่ฉันพบมักจะง่ายต่อการทดสอบ เมื่อคุณรหัสไปยังส่วนต่อประสานแทนที่จะเป็นคลาสที่เป็นรูปธรรมคุณไม่จำเป็นต้องใช้การสืบทอดเมื่อคุณทดสอบตามที่เป็นอยู่กับเฟรมเวิร์กเช่น jMock ซึ่งง่ายต่อการสร้าง mock-objects ด้วยส่วนต่อประสานมากกว่าคลาสที่เป็นรูปธรรม

ฉันเดาว่าฉันควรจะทำให้ชั้นเรียนส่วนใหญ่ของฉันเป็นที่สิ้นสุด แต่ฉันยังไม่ได้เข้าไปในห้องโถง


4

ฉันต้องอ่านรหัสจำนวนมากสำหรับงานของฉัน การขาดตัวแปรขั้นสุดท้ายในอินสแตนซ์เป็นหนึ่งในสิ่งที่ทำให้ฉันรำคาญและทำให้เข้าใจรหัสยากโดยไม่จำเป็น สำหรับเงินของฉันสุดท้ายที่ตัวแปรท้องถิ่นทำให้เกิดความยุ่งเหยิงมากกว่าความชัดเจน ภาษาควรได้รับการออกแบบมาเพื่อให้เป็นค่าเริ่มต้น แต่เราต้องอยู่กับความผิดพลาด บางครั้งมันมีประโยชน์โดยเฉพาะอย่างยิ่งกับลูปและการกำหนดที่แน่นอนกับต้นไม้ if-else แต่ส่วนใหญ่จะมีแนวโน้มที่จะระบุวิธีการของคุณซับซ้อนเกินไป


ทำไมไม่ใช้เครื่องมือที่ช่วยลดความยุ่งเหยิง?
Pacerier

@Pacerier ในการแก้ไขที่ผิดรหัส?
Tom Hawtin - tackline

3

ควรใช้ขั้นสุดท้ายอย่างชัดเจนกับค่าคงที่และบังคับใช้การเปลี่ยนแปลง แต่มีวิธีใช้ที่สำคัญอีกวิธีหนึ่ง

Java ที่มีประสิทธิภาพมีรายการทั้งหมดในรายการนี้ (รายการที่ 15) ซึ่งระบุถึงข้อผิดพลาดของการสืบทอดที่ไม่ได้ตั้งใจ อย่างมีประสิทธิภาพหากคุณไม่ได้ออกแบบและบันทึกคลาสของคุณเพื่อการสืบทอดการสืบทอดจากคลาสนั้นอาจทำให้เกิดปัญหาที่ไม่คาดคิด (ไอเท็มเป็นตัวอย่างที่ดี) ดังนั้นข้อเสนอแนะคือคุณใช้ขั้นสุดท้ายในชั้นเรียนใด ๆ และ / หรือวิธีการที่ไม่ได้ตั้งใจจะสืบทอด

นั่นอาจดูเคร่งเครียด แต่ก็สมเหตุสมผลแล้ว หากคุณกำลังเขียนไลบรารีคลาสเพื่อให้ผู้อื่นใช้งานคุณไม่ต้องการให้พวกเขาสืบทอดจากสิ่งที่ไม่ได้ออกแบบมา - คุณจะล็อคตัวเองในการใช้งานคลาสเฉพาะเพื่อความเข้ากันได้ด้านหลัง หากคุณกำลังเขียนโปรแกรมในทีมไม่มีอะไรที่จะหยุดสมาชิกคนอื่นของทีมจากการลบรอบสุดท้ายถ้าพวกเขาต้อง แต่คำหลักทำให้พวกเขาคิดเกี่ยวกับสิ่งที่พวกเขากำลังทำและเตือนพวกเขาว่าคลาสที่พวกเขาสืบทอดมานั้นไม่ได้ออกแบบมาสำหรับมันดังนั้นพวกเขาจึงควรระมัดระวังเป็นพิเศษ


3

ข้อแม้อีกประการหนึ่งคือคนจำนวนมากสับสนในขั้นสุดท้ายซึ่งหมายความว่าเนื้อหาของตัวแปรอินสแตนซ์ไม่สามารถเปลี่ยนแปลงได้มากกว่าที่การอ้างอิงไม่สามารถเปลี่ยนแปลงได้


และโพสต์นี้เป็นข้อพิสูจน์ที่ยิ่งใหญ่
inigoD

2

แม้แต่ตัวแปรท้องถิ่นการรู้ว่ามีการประกาศขั้นสุดท้ายหมายความว่าฉันไม่จำเป็นต้องกังวลเกี่ยวกับการอ้างอิงที่เปลี่ยนแปลงในภายหลัง ซึ่งหมายความว่าเมื่อทำการดีบั๊กและฉันเห็นตัวแปรนั้นในภายหลังฉันมั่นใจว่ามันหมายถึงวัตถุเดียวกัน นั่นคือสิ่งที่ฉันต้องกังวลเมื่อมองหาจุดบกพร่อง โบนัสคือถ้าหาก 99% ของตัวแปรถูกประกาศครั้งสุดท้ายตัวแปรบางตัวที่เป็นตัวแปรนั้นจะโดดเด่นกว่า นอกจากนี้สุดท้ายให้คอมไพเลอร์พบข้อผิดพลาดโง่ที่เป็นไปได้มากกว่าที่อาจจะไม่มีใครสังเกตเห็น


2

การเลือกพิมพ์finalสำหรับแต่ละพารามิเตอร์ในแต่ละวิธีจะทำให้เกิดการระคายเคืองอย่างมากทั้งสำหรับโค้ดและเครื่องอ่านโค้ด

เมื่อการระคายเคืองเปลี่ยนไปเกินกว่าที่ควรจะเปลี่ยนเป็น Scala ซึ่งข้อโต้แย้งถือเป็นที่สิ้นสุดโดยค่าเริ่มต้น

หรือคุณสามารถใช้เครื่องมือกำหนดสไตล์โค้ดที่จะทำโดยอัตโนมัติให้กับคุณ IDE ทั้งหมดมีการนำไปใช้งานหรือเป็นปลั๊กอิน


1

ขั้นสุดท้ายเมื่อใช้กับตัวแปรใน Java จัดเตรียมทดแทนสำหรับค่าคงที่ใน C ++ ดังนั้นเมื่อใช้ขั้นตอนสุดท้ายและแบบคงที่สำหรับตัวแปรมันจะไม่เปลี่ยนรูป ในขณะเดียวกันก็ทำให้โปรแกรมเมอร์ C ++ ที่ย้ายข้อมูลมีความสุขมาก ;-)

เมื่อใช้กับตัวแปรอ้างอิงมันไม่อนุญาตให้คุณอ้างอิงวัตถุอีกครั้งแม้ว่าวัตถุนั้นสามารถถูกจัดการได้

เมื่อขั้นตอนสุดท้ายถูกใช้กับเมธอดจะไม่อนุญาตให้เมธอดถูกลบล้างโดยคลาสย่อย

เมื่อการใช้งานชัดเจนมากควรใช้ด้วยความระมัดระวัง ส่วนใหญ่ขึ้นอยู่กับการออกแบบว่าการใช้ขั้นตอนสุดท้ายจะไม่ช่วยให้เกิดความแตกต่าง

หนึ่งควรใช้สำหรับตัวแปรเมื่อคุณแช่งให้แน่ใจว่าค่าของตัวแปรจะ / ไม่ควรเปลี่ยน และตรวจสอบให้แน่ใจว่าคุณปฏิบัติตามระเบียบการเข้ารหัสที่สนับสนุนโดย SUN.for เช่น: int สุดท้าย COLOR_RED = 1; (ตัวพิมพ์ใหญ่คั่นด้วยเครื่องหมายขีดล่าง)

ด้วยตัวแปรอ้างอิงใช้เฉพาะเมื่อเราต้องการการอ้างอิงที่ไม่เปลี่ยนรูปแบบไปยังวัตถุเฉพาะ

เกี่ยวกับส่วนที่สามารถอ่านได้แสดงว่าความคิดเห็นมีบทบาทสำคัญมากเมื่อใช้ตัวแก้ไขสุดท้าย


มีคนบอกฉันหน่อยได้ไหมว่าทำไมเรื่องนี้ถึงลงคะแนน ??? เพียงแค่อยากรู้อยากเห็น ..
อำนาจทุกคน

อาจเป็นเพราะคุณระบุว่าคุณควรทำให้มันสุดท้ายเท่านั้นเมื่อ XYZ คนอื่น ๆ คิดว่ามันเป็นการปฏิบัติที่ดีกว่าที่จะทำให้ทุกอย่างเป็นที่สุดเว้นแต่จะมีความจำเป็นต้องทำเช่นนั้น
Outlaw Programmer

1
มันไม่ได้แทนคำหลัก C ++ const -1
tmj

1

ฉันไม่เคยใช้มันในตัวแปรท้องถิ่นมีจุดเล็ก ๆ สำหรับการใช้คำฟุ่มเฟื่อยเพิ่ม แม้ว่าคุณจะไม่คิดว่าควรกำหนดตัวแปรใหม่ แต่จะสร้างความแตกต่างเล็กน้อยให้กับบุคคลถัดไปที่แก้ไขโค้ดนั้นที่คิดเป็นอย่างอื่นและเนื่องจากรหัสจะถูกเปลี่ยนวัตถุประสงค์เดิมใด ๆ ที่ทำให้การใช้งานอาจไม่สมบูรณ์อีกต่อไป หากเป็นเพียงเพื่อความชัดเจนฉันเชื่อว่ามันล้มเหลวเนื่องจากผลกระทบเชิงลบของการใช้คำฟุ่มเฟื่อย

ค่อนข้างเหมือนกันกับตัวแปรสมาชิกเช่นกันเพราะพวกเขาให้ผลประโยชน์น้อยยกเว้นในกรณีของค่าคงที่

นอกจากนี้ยังไม่มีผลกระทบต่อการเปลี่ยนแปลงไม่ได้เนื่องจากตัวบ่งชี้ที่ดีที่สุดของสิ่งที่ไม่เปลี่ยนรูปนั้นคือมีการบันทึกไว้เช่นและ / หรือไม่มีวิธีการที่สามารถแก้ไขวัตถุ (สิ่งนี้รวมถึงการทำให้ชั้นเรียนสุดท้ายเป็นวิธีเดียวที่รับประกันได้ว่า มันไม่เปลี่ยนรูป)

แต่เดี๋ยวก่อนนั่นเป็นเพียงความคิดเห็นของฉัน :-)


1

ฉันตั้งค่า Eclipse เพื่อเพิ่มครั้งสุดท้ายในทุกฟิลด์และคุณลักษณะที่ไม่ได้แก้ไข ใช้งานได้ดีโดยใช้ Eclipse "บันทึกการกระทำ" ซึ่งจะเพิ่มตัวดัดแปลงสุดท้ายเหล่านี้ (เหนือสิ่งอื่นใด) เมื่อบันทึกไฟล์

แนะนำเป็นอย่างยิ่ง

ลองดูโพสต์บล็อกของฉันจาก Eclipse Save Actions


1

สำหรับข้อโต้แย้งฉันคิดว่าพวกเขาไม่ต้องการ Mostley พวกเขาเพียงแค่ทำร้ายความพร้อมในการอ่าน การกำหนดค่าตัวแปรอาร์กิวเมนต์ซ้ำ ๆ นั้นช่างโง่เหลือเกินที่ฉันควรจะค่อนข้างมั่นใจว่าพวกเขาจะได้รับการปฏิบัติเหมือนเป็นค่าคงเดิม

ความจริงที่ว่าสี Eclipse สีแดงขั้นสุดท้ายทำให้ง่ายต่อการสังเกตการประกาศตัวแปรในรหัสซึ่งฉันคิดว่าช่วยเพิ่มความสามารถในการอ่านได้มากที่สุด

ฉันพยายามที่จะบังคับใช้กฎว่าตัวแปรใด ๆ และทั้งหมดควรเป็นที่สิ้นสุดเพราะไม่มีเหตุผลที่ดีที่สุดสำหรับ extremley มันง่ายกว่ามากที่จะตอบว่า "ตัวแปรนี้คืออะไร" คำถามหากคุณเพียงแค่ต้องค้นหาการเริ่มต้นและมั่นใจว่าเป็น

จริง ๆ แล้วฉันค่อนข้างกังวลเกี่ยวกับตัวแปรที่ไม่ใช่ตอนนี้ต่อวัน มันเหมือนกับความแตกต่างระหว่างการมีดที่แขวนอยู่ในด้ายอยู่เหนือหัวของคุณหรือเพียงแค่มีลิ้นชักครัวของคุณ ...

ตัวแปรสุดท้ายเป็นเพียงวิธีที่ดีในการเขียนค่า

ตัวแปรที่ไม่สิ้นสุดถูกผูกไว้กับส่วนหนึ่งของอัลกอริทึมข้อผิดพลาดบางอย่าง

คุณลักษณะที่ดีอย่างหนึ่งคือเมื่อตัวเลือกในการใช้ตัวแปรหมดคำถามสำหรับอัลกอริทึมส่วนใหญ่เวลาที่การแก้ปัญหาคือการเขียนวิธีการแทนซึ่งมักจะปรับปรุงรหัสอย่างมีนัยสำคัญ


1

ฉันได้รับการเข้ารหัสในขณะนี้และใช้สุดท้ายเมื่อใดก็ตามที่ฉันสามารถ หลังจากทำสิ่งนี้ไประยะหนึ่ง (สำหรับตัวแปรพารามิเตอร์เมธอดและแอตทริบิวต์คลาส) ฉันสามารถพูดได้ว่า 90% (หรือมากกว่า) ของตัวแปรของฉันถือเป็นที่สิ้นสุด ฉันคิดว่าประโยชน์ของการไม่มีการแก้ไขตัวแปรเมื่อคุณไม่ต้องการ (ฉันเคยเห็นมาก่อนและบางครั้งก็เจ็บปวด) จ่ายสำหรับการพิมพ์เพิ่มเติมและคำหลัก "สุดท้าย" พิเศษในรหัสของคุณ

ที่ถูกกล่าวว่าถ้าฉันจะออกแบบภาษาฉันจะทำให้ทุกตัวแปรสุดท้ายจนกว่าจะมีการแก้ไขโดยคำหลักอื่น ๆ

ฉันไม่ได้ใช้ขั้นสุดท้ายมากมายในการเรียนและวิธีการคิด นี่คือตัวเลือกการออกแบบที่ซับซ้อนมากขึ้นหรือน้อยลงยกเว้นว่าคลาสของคุณเป็นคลาสยูทิลิตี้ (ซึ่งในกรณีนี้คุณควรมีคอนสตรัคเตอร์ส่วนตัวเดียวเท่านั้น)

ฉันยังใช้ Collections.unmodifiable ... เพื่อสร้างรายการที่ไม่สามารถเปลี่ยนแปลงได้เมื่อฉันต้องการ


0

การใช้คลาสโลคัลที่ไม่ระบุชื่อสำหรับผู้ฟังเหตุการณ์และเป็นรูปแบบทั่วไปใน Java การใช้คำหลักขั้นสุดท้ายที่พบบ่อยที่สุดคือการทำให้แน่ใจว่าตัวแปรในขอบเขตสามารถเข้าถึงได้โดยผู้ฟังคู่

อย่างไรก็ตามหากคุณพบว่าตัวเองจำเป็นต้องใส่งบจำนวนมากในรหัสของคุณ นั่นอาจเป็นคำใบ้ที่ดีว่าคุณกำลังทำอะไรผิด

บทความที่โพสต์ข้างต้นแสดงตัวอย่างนี้:

public void doSomething(int i, int j) {
    final int n = i + j; // must be declared final

    Comparator comp = new Comparator() {
        public int compare(Object left, Object right) {
            return n; // return copy of a local variable
        }
    };
}

0

ฉันใช้สำหรับค่าคงที่ทั้งภายในและภายนอก

บางครั้งฉันก็ใช้มันสำหรับวิธีการเพราะฉันไม่รู้ว่า subclass จะไม่ต้องการแทนที่วิธีที่กำหนด (ด้วยเหตุผลใดก็ตาม)

สำหรับคลาสแล้วสำหรับคลาสโครงสร้างพื้นฐานเท่านั้นฉันได้ใช้คลาสสุดท้ายแล้ว

IntelliJ IDEA เตือนคุณหากมีการเขียนพารามิเตอร์ฟังก์ชันไว้ในฟังก์ชัน ดังนั้นฉันจึงหยุดใช้สุดท้ายสำหรับอาร์กิวเมนต์ฟังก์ชัน ฉันไม่เห็นพวกเขาในไลบรารี java Runtime เช่นกัน


0

ฉันแทบจะไม่ใช้ขั้นตอนสุดท้ายเกี่ยวกับวิธีการหรือชั้นเรียนเพราะฉันชอบให้ผู้คนแทนที่พวกเขา

มิฉะนั้นฉันจะใช้ในที่สุดถ้ามันเป็น public/private static final type SOME_CONSTANT;


อืม.. แก้ไข ณ ที่แห่งหนึ่ง .. ยังบอกว่าในที่สุดบรรทัดที่สอง ;-)
อำนาจทุกคน

การอนุญาตให้ผู้คนแทนที่ค่าเป็นแหล่งที่มาของความประหลาดใจที่ใหญ่ที่สุดแหล่งเดียวและข้อบกพร่องที่ยากต่อการคิด
RAY

0

การทำเครื่องหมายในชั้นเรียนสุดท้ายยังสามารถทำให้การผูกวิธีบางอย่างเกิดขึ้นในเวลาคอมไพล์แทนการใช้งานจริง พิจารณา "v2.foo ()" ด้านล่าง - คอมไพเลอร์รู้ว่า B ไม่สามารถมีคลาสย่อยได้ดังนั้น foo () จึงไม่สามารถถูกแทนที่ได้ดังนั้นการใช้งานการโทรจึงเป็นที่รู้จักในเวลารวบรวม หากคลาส B ไม่ถูกทำเครื่องหมายสุดท้ายอาจเป็นไปได้ว่าประเภท v2 จริงเป็นคลาสที่ขยาย B และแทนที่ foo ()

class A {
    void foo() {
        //do something
    }
}
final class B extends A {
    void foo() {
    }
}
class Test {
    public void t(A v1, B v2) {
        v1.foo();
        v2.foo();
    }
}

-1

ขอแนะนำให้ใช้ขั้นสุดท้ายสำหรับค่าคงที่ อย่างไรก็ตามฉันจะไม่ใช้มันสำหรับวิธีการหรือชั้นเรียน (หรืออย่างน้อยคิดเกี่ยวกับมันในขณะที่) เพราะมันทำให้การทดสอบยากขึ้นถ้าเป็นไปไม่ได้ หากคุณต้องทำให้คลาสหรือวิธีการสุดท้ายแน่นอนตรวจสอบให้แน่ใจว่าชั้นนี้ใช้อินเทอร์เฟซบางอย่างเพื่อให้คุณสามารถจำลองการใช้อินเทอร์เฟซเดียวกัน


มันไม่ได้ทำให้การทดสอบหนักขึ้นเพราะคุณควรใช้อินเตอร์เฟสอยู่แล้ว
คริส Vest
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.