ทำไมคำหลัก 'สุดท้าย' จึงมีการใช้งานเพียงเล็กน้อยในอุตสาหกรรมนี้ [ปิด]


14

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

แต่ยิ่งกว่าทุกสิ่งมันมีส่วนทำให้การออกแบบมีความแข็งแกร่งยิ่งขึ้นต่อการเปลี่ยนแปลงและให้คำแนะนำแก่ผู้มอบหมายอื่น ๆ เมื่อพวกเขาต้องการแก้ไขฐานรหัส

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

มีเหตุผลหรือไม่? มันเป็นกระบวนทัศน์การออกแบบทั่วไปเพื่อให้ทุกอย่างไม่แน่นอนจากภายในหรือไม่


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

5
@ วงล้อ: ฉันคิดว่านี่เป็นเรื่องเกี่ยวกับการทำให้ชั้นเรียนของคุณไม่เปลี่ยนรูปเช่นเดียวกับในการเขียนโปรแกรมการทำงาน
Jonas

@Kwebble: บางทีที่สำคัญกว่านั้นอินสแตนซ์สตริงแต่ละอันไม่เปลี่ยนรูป
MatrixFrog

คำตอบ:


9

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

ลองดูโครงการโอเพนซอร์สที่ดีและฉันคิดว่าคุณจะพบมากขึ้น

ตรงกันข้ามกับสิ่งที่คุณเห็นใน Java ในโลก. NET ฉันเคยได้ยินข้อโต้แย้งหลายครั้งว่าประโยคควรจะsealed(คล้ายกับขั้นสุดท้ายที่ใช้กับคลาส) โดยค่าเริ่มต้นและผู้พัฒนาควรยกเลิกการปิดผนึกอย่างชัดเจน มัน.


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

1
@ Aurélien: ถ้ามันทำให้คุณรู้สึกดีขึ้นคลาสต่างๆใน. NET Framework นั้นถูกผนึกไว้ทำให้ผู้ใช้บางคนที่ต้องการขยายคลาสของเฟรมเวิร์กด้วยฟังก์ชันของตนเอง อย่างไรก็ตามข้อ จำกัด นี้สามารถบรรเทาได้บ้างโดยใช้วิธีการขยาย
Robert Harvey

1
ฉันคิดว่านี่เป็นเรื่องเกี่ยวกับการเปลี่ยนแปลงไม่ได้มากกว่าการหลีกเลี่ยงส่วนขยาย กล่าวอีกนัยหนึ่งการใช้finalฟิลด์บนไม่ใช่วิธีการ คลาสที่ไม่เปลี่ยนรูปอาจถูกออกแบบมาให้ขยายออกไป
Jonas

15

ปัญหาเกี่ยวกับการใช้finalเพื่อสื่อว่าสิ่งที่เป็นแบบอ่านอย่างเดียวคือมันใช้งานได้กับประเภทดั้งเดิมเช่นintเท่านั้นcharเป็นต้นวัตถุทั้งหมดใน Java ถูกอ้างถึงโดยใช้ตัวชี้ (ชนิด) ดังนั้นเมื่อคุณใช้finalคำสำคัญบนวัตถุคุณกำลังบอกว่าการอ้างอิงเป็นแบบอ่านอย่างเดียวเท่านั้นเองวัตถุนั้นยังคงไม่แน่นอน

อาจมีการใช้งานมากกว่านี้หากทำให้วัตถุเป็นแบบอ่านอย่างเดียว ใน C ++ นั้นเป็นสิ่งที่constเกิดขึ้นจริงและเป็นคำหลักที่มีประโยชน์และใช้งานมาก

ที่เดียวที่ฉันใช้finalคำหลักอย่างหนักคือมีพารามิเตอร์เพื่อหลีกเลี่ยงความสับสนที่สร้างขึ้นโดยสิ่งต่าง ๆ เช่นนี้:

public void someMethod(FancyObject myObject) {
    myObject = new FancyObject();
    myObject.setProperty(7);
}
...
public static void main(final String[] args) {
    ...
    FancyObject myObject = new FancyObject();
    someOtherObject.someMethod(myObject);
    myObject.getProperty(); // Not 7!
}

ในตัวอย่างนี้ดูเหมือนชัดเจนว่าทำไมสิ่งนี้ถึงใช้งานไม่ได้ แต่หากsomeMethod(FancyObject)ความสับสนใหญ่โตและซับซ้อนสามารถเกิดขึ้นได้ ทำไมไม่หลีกเลี่ยงมันล่ะ

เป็นส่วนหนึ่งของ Sun (หรือ Oracle ตอนนี้ฉันเดา) มาตรฐานการเข้ารหัส


1
หากมีการใช้งานมากขึ้นfinalในคลาส Java API วัตถุส่วนใหญ่จะไม่เปลี่ยนรูปเหมือนไลบรารี Scala จำนวนมาก จากนั้นการสร้างฟิลด์วัตถุfinalทำให้คลาสไม่เปลี่ยนแปลงในหลาย ๆ กรณี การออกแบบนี้จะถูกใช้ไปแล้วในและBigDecimal String
Jonas

@ Jonas ฉันอ่านคำถามเกี่ยวกับจุดที่ 4 ในคำตอบของ schmmd ตั้งแต่ที่เขาพูดว่า "เนื่องจากผู้คนสามารถเห็นตัวแปรที่อ่านได้อย่างเดียว" และตอบตามนั้น บางทีฉันควรรวมสมมติฐานนั้นไว้ในคำตอบ
Gyan aka Gary Buyn

โปรดทราบว่ามีเวลาที่คุณต้องการมอบหมายพารามิเตอร์อีกครั้ง ตัวอย่างคือการตัดพารามิเตอร์สตริง
Steve Kuo

@ Steve ฉันมักจะสร้างตัวแปรใหม่ที่จะได้รับมอบหมายในสถานการณ์นั้น
Gyan aka Gary Buyn

1
@ แกรี่สำหรับฉันอย่างน้อยมันก็หายากมากที่ข้อบกพร่อง / ความสับสนเกิดจากการกำหนดพารามิเตอร์ใหม่ ฉันอยากจะมีรหัสฟรีถ่วงและยอมรับโอกาสระยะไกลของการกำหนดพารามิเตอร์ที่ทำให้เกิดข้อผิดพลาด เพียงระวังเมื่อเขียน / แก้ไขรหัส
Steve Kuo

4

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

บางภาษาอื่น ๆ เช่นสกาล่า, ทำให้มันง่ายมากที่จะทำให้การประกาศครั้งสุดท้าย ( Val ) ในภาษาเหล่านี้การประกาศขั้นสุดท้ายอาจเป็นเรื่องธรรมดามากกว่าตัวแปร

โปรดทราบว่ามีการใช้คำหลักสุดท้ายที่แตกต่างกันมากมาย โพสต์ของคุณส่วนใหญ่ครอบคลุมรายการ 2 และ 3

  1. คลาสสุดท้าย (JLS 8.1.1.2)
  2. เขตข้อมูลสุดท้าย (JLS 8.3.1.2)
  3. วิธีสุดท้าย (JLS 8.4.3.3)
  4. ตัวแปรสุดท้าย (JLS 4.12.4)

2

ดีที่จะเริ่มต้นด้วย Java อย่างเป็นทางการอนุสัญญารหัสfinalค่าความโปรดปรานมิได้ห้ามการใช้งานในด้านการ นั่นคือนักพัฒนา JDK มีอิสระที่จะเลือกวิธีที่พวกเขาต้องการ

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

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

มันอาจช่วยเพิ่ม JIT เล็กน้อยและในขณะที่ จำกัด มากมันไม่เป็นอันตราย

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


2

เมื่อเร็ว ๆ นี้ฉันค้นพบความสุขของคุณสมบัติ "บันทึกการกระทำ" ใน Eclipse IDE ฉันสามารถบังคับให้ฟอร์แมตรหัสของฉันหายไปใส่@Overrideคำอธิบายประกอบและทำสิ่งที่ดีบางอย่างเช่นการลบวงเล็บที่ไม่จำเป็นในการแสดงออกหรือใส่คำหลักทุกที่โดยอัตโนมัติทุกครั้งที่ผมตีfinal ctrl + Sฉันเปิดใช้ทริกเกอร์เหล่านั้นแล้วเด็กชายมันช่วยได้มาก!

ปรากฎว่าผู้กระตุ้นเหล่านั้นทำตัวเหมือนการตรวจสติอย่างรวดเร็วสำหรับรหัสของฉัน

  • ฉันตั้งใจจะลบล้างวิธีการ แต่คำอธิบายประกอบไม่ปรากฏเมื่อฉันกดปุ่มctrl + s? - บางทีฉันอาจทำให้พารามิเตอร์ผิดพลาดบางแห่ง!
  • วงเล็บบางส่วนถูกลบออกจากรหัสเมื่อบันทึก? - บางทีการแสดงออกทางตรรกะนั้นเป็นวิธีที่ยากเกินไปสำหรับโปรแกรมเมอร์ที่จะไปไหนมาไหนด้วยความรวดเร็ว มิฉะนั้นทำไมฉันต้องเพิ่มวงเล็บเหล่านั้นในตอนแรก
  • finalพารามิเตอร์หรือตัวแปรไม่ได้ มันต้องเปลี่ยนค่าหรือไม่?

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

โอ้ฉันเกลียดการแก้จุดบกพร่อง! เวลาผมทำงานดีบักฉันรู้สึกเหมือนเวลาของฉันแต่ละคนจะวิ่งออกมาและฉันหมดต้องใช้เวลาที่จะทำอย่างน้อยบางส่วนของความฝันวัยเด็กของฉันจะกลายเป็นความจริง! ไปสู่นรกด้วยการดีบั๊ก! finalหมายความว่าไม่มีการเปลี่ยนแปลงค่าลึกลับอีกต่อไป More finals => ชิ้นส่วนที่บอบบางน้อยลงในรหัสของฉัน => less bugs => มีเวลามากขึ้นในการทำสิ่งดีๆ!

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


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


1
คุณอาจลองพิจารณาภาษาที่ใช้งานได้เช่น OCaml หรือ F # ภาษาเหล่านี้มีแนวโน้มที่จะต้องมีการดีบักน้อยกว่าซึ่งเป็นหนึ่งในสาเหตุที่ทุกอย่างเป็นแบบอ่านอย่างเดียวโดยค่าเริ่มต้น ใส่เพียงครั้งเดียวได้รับมอบหมายตัวแปรในภาษาการทำงานจะไม่เปลี่ยนแปลง
อาเบล

1
ใช่ฉันรู้และจริง ๆ แล้วฉันเขียนรหัส ML บางครั้ง - นั่นคือสิ่งที่ฉันได้รับแรงบันดาลใจจาก :) มันไม่เกี่ยวกับภาษาที่คุณใช้ แต่เกี่ยวกับหลักการและเทคนิคที่คุณใช้ หนึ่งสามารถไปทั้งหมดจำเป็นด้วย Haskell และdoสัญกรณ์ :) แน่นอนว่า Java ไม่ได้เป็นภาษาที่ดีที่สุดสำหรับการเขียนในรูปแบบการทำงาน แต่อย่างน้อยก็ช่วยให้คุณเขียนรหัสที่มีประสิทธิภาพ - และนั่นคือสิ่งที่ฉันสนใจจริงๆ
Andrew АндрейЛисточкин
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.