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


171

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

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

เป็นสิ่งที่ฉันควรจะพยายามจดจำหรือไม่?


นี่คือโพสต์ที่เกี่ยวข้องเพื่อค้นหา: stackoverflow.com/questions/137868/…
mattlant

3
รายการซ้ำซ้อนของ: stackoverflow.com/questions/137868/ …
Alex Miller

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

คำตอบ:


178

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

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

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

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

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

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

  • แก้ไข: โปรดทราบว่ากรณีการใช้งานหนึ่งกรณีที่ตัวแปรท้องถิ่นสุดท้ายมีประโยชน์อย่างมากตามที่ระบุโดย@ adam-gentคือเมื่อค่าถูกกำหนดให้กับ var ในif/ elseสาขา


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

61
ด้วยความเคารพจาก Josh Bloch (และนั่นเป็นจำนวนมาก) ฉันไม่เห็นด้วยกับกรณีทั่วไป ในกรณีของการสร้าง API ให้แน่ใจว่าล็อคสิ่งต่าง ๆ ลง ภายในรหัสของคุณเองการสร้างกำแพงที่คุณต้องรื้อในภายหลังนั้นเป็นการเสียเวลา
Alex Miller

9
แน่นอนว่าไม่ใช่ "เสียเวลา" เป็นพิเศษเพราะไม่มีค่าใช้จ่ายเลย ... ในแอปพลิเคชันปกติแล้วฉันจะสร้างคลาสเกือบทุกคลาสfinalตามค่าเริ่มต้น คุณอาจไม่สังเกตเห็นประโยชน์เว้นแต่ว่าคุณจะใช้ Java IDE ที่ทันสมัยอย่างแท้จริง (เช่น IDEA)
Rogério

9
IDEA มีการตรวจสอบโค้ดหลายร้อย (นอกกรอบ) และบางรายการสามารถตรวจจับโค้ดที่ไม่ได้ใช้ / ไม่จำเป็นในfinalคลาส / วิธีการ ตัวอย่างเช่นหากวิธีสุดท้ายประกาศว่าจะโยนข้อยกเว้นที่ตรวจสอบ แต่ไม่เคยโยนจริง IDEA จะแจ้งให้คุณทราบและคุณสามารถลบข้อยกเว้นออกจากthrowsข้อ บางครั้งคุณยังสามารถค้นหาวิธีการทั้งหมดที่ไม่ได้ใช้ซึ่งสามารถตรวจพบได้เมื่อไม่สามารถ overriden
Rogério

8
@rmaruszewski คลาสการทำเครื่องหมายเป็นขั้นสุดท้ายช่วยป้องกันกรอบการเยาะเย้ยที่สุดจากความสามารถในการเยาะเย้ยพวกเขาจึงทำให้คุณรหัสยากที่จะทดสอบ ฉันจะทำให้ชั้นเรียนสุดท้ายถ้ามันสำคัญอย่างยิ่งที่จะไม่ขยาย
Mike Rylander

44

มันเป็นสิ่งที่ฉันควรใช้ความพยายามในการจำที่จะทำ?

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


3
ทิปที่ยอดเยี่ยมสำหรับ Save Action ไม่รู้เกี่ยวกับสิ่งนั้น
สติ

1
ผมส่วนใหญ่พิจารณาจากผลประโยชน์ที่สุดท้ายทำให้รหัสปลอดภัยจากข้อผิดพลาดโดยไม่ได้ตั้งใจที่จะกำหนดตัวแปรผิดมากกว่า optimisations ใด ๆ ที่อาจจะหรืออาจจะไม่เกิดขึ้น
ปีเตอร์ฮิลตัน

4
นี่เป็นปัญหาสำหรับคุณจริงๆเหรอ? คุณมีข้อบกพร่องที่เกิดจากสิ่งนี้บ่อยแค่ไหน?
Alex Miller

1
+1 สำหรับเคล็ดลับที่มีประโยชน์ใน Eclipse ฉันคิดว่าเราควรใช้สุดท้ายให้มากที่สุดเพื่อหลีกเลี่ยงข้อบกพร่อง
emeraldhieu

คุณสามารถทำสิ่งนี้ใน IntelliJ ได้หรือไม่?
Koray Tugay

15

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

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

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

การทำเครื่องหมายวิธี "final" มีประโยชน์ในคลาสนามธรรม มันอธิบายอย่างชัดเจนว่าจุดส่วนขยายอยู่ที่ใด


11

ฉันใช้finalตลอดเวลาเพื่อทำให้ Java แสดงออกมากขึ้น ดูเงื่อนไขของ Java (if,else,switch ) ไม่ได้แสดงออกตามที่ฉันเกลียดเสมอโดยเฉพาะถ้าคุณใช้ในการเขียนโปรแกรมการทำงาน (เช่น ML, Scala หรือ Lisp)

ดังนั้นคุณควรพยายาม (IMHO) ใช้ตัวแปรสุดท้ายเสมอเมื่อใช้เงื่อนไข

ผมขอยกตัวอย่าง:

    final String name;
    switch(pluginType) {
        case CANDIDATE_EXPORT:
            name = "Candidate Stuff";
            break;
        case JOB_POSTING_IMPORT:
            name = "Blah";
            break;
        default:
            throw new IllegalStateException();
    }

ตอนนี้ถ้าเพิ่มcaseคำสั่งอื่นและไม่ได้ตั้งค่าnameคอมไพเลอร์จะล้มเหลว คอมไพเลอร์จะล้มเหลวถ้าคุณไม่ทำทุกกรณี (ที่คุณตั้งค่าตัวแปร) สิ่งนี้ทำให้คุณสามารถทำให้ Java คล้ายกับ Lisp ได้มากletนิพจน์และทำให้โค้ดของคุณไม่ได้ถูกเยื้องอย่างหนาแน่น (เนื่องจากตัวแปรการกำหนดขอบเขตของคำศัพท์)

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

    String name;
    switch(pluginType) {
        case CANDIDATE_EXPORT:
            name = "Candidate Stuff";
            //break; whoops forgot break.. 
            //this will cause a compile error for final ;P @Recurse
        case JOB_POSTING_IMPORT:
            name = "Blah";
            break;
    }
    // code, code, code
    // Below is not possible with final
    name = "Whoops bug";

เนื่องจากชื่อการตั้งค่าข้อผิดพลาด (นอกจากลืมไปbreakที่ข้อผิดพลาดอื่น) ตอนนี้ฉันสามารถทำสิ่งนี้โดยไม่ได้ตั้งใจ:

    String name;
    switch(pluginType) {
        case CANDIDATE_EXPORT:
            name = "Candidate Stuff";
            break;
        //should have handled all the cases for pluginType
    }
    // code, code, code
    // Below is not possible with final
    name = "Whoops bug";

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

ข้างต้นใน OCaml:

type plugin = CandidateExport | JobPostingImport

let p = CandidateExport

let name = match p with
    | CandidateExport -> "Candidate Stuff"
    | JobPostingImport -> "Blah" ;;

การmatch ... with ...ประเมินผลเช่นฟังก์ชั่นเช่นการแสดงออก สังเกตว่ามันดูเหมือนคำสั่งเปลี่ยนของเรา

นี่คือตัวอย่างใน Scheme (แร็กเก็ตหรือไก่):

(define name 
    (match b
      ['CandidateExport "Candidate Stuff"]
      ['JobPostingImport "Blah"]))

1
ยกเว้นว่าคอมไพเลอร์ java จะให้ข้อผิดพลาด "ชื่อที่อาจไม่เริ่มต้น" และปฏิเสธที่จะคอมไพล์ด้วยหรือไม่ใช้ขั้นสุดท้าย
ชดเชย

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

9

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

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

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


1
จุดสุดท้ายที่ถูกต้องมากแม้ว่าฉันจะล้มเลิกความยาวของตัวอักษร 80 ตัวเมื่อนานมาแล้วเนื่องจากความละเอียดหน้าจอเปลี่ยนไปเล็กน้อยในช่วง 10 ปีที่ผ่านมา ฉันสามารถใส่ถ่านขนาด 300 เส้นบนหน้าจอได้อย่างง่ายดายโดยไม่ต้องเลื่อน อย่างไรก็ตามความสามารถในการอ่านนั้นดีกว่าโดยไม่มีfinalพารามิเตอร์มาก่อน
brimborium

8

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

ฉันชอบใช้คำฟุ่มเฟื่อยน้อยที่สุดดังนั้นฉันจึงมักจะหลีกเลี่ยงการใช้คำหลักพิเศษที่ไม่จำเป็นจริงๆ

ฉันชอบภาษาที่มีพลวัต แต่ก็ไม่น่าแปลกใจที่ฉันต้องการหลีกเลี่ยงการใช้คำฟุ่มเฟื่อย

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


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


6

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

 public int processSomethingCritical( final int x, final int y ){
 // hundreds of lines here 
     // for loop here...
         int x2 = 0;
        x++; // bug aarrgg...
 // hundreds of lines there
 // if( x == 0 ) { ...

 }

แน่นอนในโลกที่สมบูรณ์แบบนี้จะไม่เกิดขึ้น แต่ .. ดี .. บางครั้งคุณต้องสนับสนุนรหัสอื่น ๆ :(


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

2
หากคุณมี "โค้ดหลายร้อยบรรทัด" ในวิธีการเดียวคุณอาจต้องการแบ่งออกเป็นวิธีเล็ก ๆ หลายวิธี
Steve Kuo

5

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

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


4

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


2

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

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

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


2

finalมีการใช้หลายตัวแปรที่มี นี่เป็นเพียงไม่กี่

ค่าคงที่สุดท้าย

 public static class CircleToolsBetter {
     public final static double PI = 3.141;
        public double getCircleArea(final double radius) {
          return (Math.pow(radius, 2) * PI);
        }
    }

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

ตัวแปรสุดท้าย

public static String someMethod(final String environmentKey) {
    final String key = "env." + environmentKey;
    System.out.println("Key is: " + key);
    return (System.getProperty(key));

  }

}

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

public class FinalVariables {


  public final static void main(final String[] args) {
    System.out.println("Note how the key variable is changed.");
    someMethod("JAVA_HOME");
    someMethod("ANT_HOME");
  }
}

ค่าคงที่สุดท้าย

public double equation2Better(final double inputValue) {
    final double K = 1.414;
    final double X = 45.0;

double result = (((Math.pow(inputValue, 3.0d) * K) + X) * M);
double powInputValue = 0;         
if (result > 360) {
  powInputValue = X * Math.sin(result); 
} else {
  inputValue = K * Math.sin(result);   // <= Compiler error   
}

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

คอลเลกชันสุดท้าย

กรณีที่แตกต่างกันเมื่อเรากำลังพูดถึงคอลเลกชันคุณจะต้องตั้งค่าให้พวกเขาเป็น unmodifiable

 public final static Set VALID_COLORS; 
    static {
      Set temp = new HashSet( );
      temp.add(Color.red);
      temp.add(Color.orange);
      temp.add(Color.yellow);
      temp.add(Color.green);
      temp.add(Color.blue);
      temp.add(Color.decode("#4B0082")); // indigo
      temp.add(Color.decode("#8A2BE2")); // violet
      VALID_COLORS = Collections.unmodifiableSet(temp);
    }

มิฉะนั้นหากคุณไม่ตั้งเป็น unmodifiable:

Set colors = Rainbow.VALID_COLORS;
colors.add(Color.black); // <= logic error but allowed by compiler

ชั้นเรียนสุดท้ายและวิธีสุดท้ายไม่สามารถขยายหรือเขียนทับได้ตามลำดับ

แก้ไข: เพื่อระบุปัญหาระดับสุดท้ายที่เกี่ยวกับการคำนวณ:

มีสองวิธีในการทำให้ชั้นเรียนเป็นขั้นสุดท้าย สิ่งแรกคือการใช้คำสำคัญสุดท้ายในการประกาศคลาส:

public final class SomeClass {
  //  . . . Class contents
}

วิธีที่สองในการทำให้คลาสสุดท้ายคือประกาศสิ่งก่อสร้างทั้งหมดเป็นแบบส่วนตัว:

public class SomeClass {
  public final static SOME_INSTANCE = new SomeClass(5);
  private SomeClass(final int value) {
  }

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

public class Test{
  private Test(Class beanClass, Class stopClass, int flags)
    throws Exception{
    //  . . . snip . . . 
  }
}

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

ดังนั้นคุณควรทำเครื่องหมายเป็นขั้นสุดท้ายเมื่อคุณสร้างคลาสโดยปริยายโดยทำให้เป็นคอนสตรัคเตอร์ส่วนตัว


1

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


1

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

นอกจากนั้นสิ่งที่คุณพูดถูกต้อง


ตอนนี้ java 8 นำเสนอความยืดหยุ่นด้วยตัวแปรสุดท้ายที่มีประสิทธิภาพ
Ravindra babu

0

ใช้ finalคำสำคัญสำหรับตัวแปรถ้าคุณทำให้ตัวแปรนั้นเป็นimmutable

โดยการประกาศตัวแปรเป็นขั้นสุดท้ายจะช่วยให้นักพัฒนาสามารถแยกแยะปัญหาการแก้ไขที่เป็นไปได้ของตัวแปรในสภาพแวดล้อมแบบมัลติเธรดสูง

ด้วยการเปิดตัว Java 8 เรามีแนวคิดอีกหนึ่งแนวคิดที่เรียกว่า " effectively final variable" ตัวแปรที่ไม่ใช่ครั้งสุดท้ายสามารถยกเป็นตัวแปรสุดท้ายได้

ตัวแปรท้องถิ่นที่อ้างอิงจากนิพจน์แลมบ์ดาต้องเป็นที่สิ้นสุด

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

จนถึง Java 7 คุณไม่สามารถใช้ตัวแปรโลคอลที่ไม่ใช่ขั้นสุดท้ายภายในคลาสนิรนาม แต่จาก Java 8 คุณสามารถทำได้

ดูที่บทความนี้


-1

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

final int CM_PER_INCH = 2.54;

คุณจะประกาศตัวแปรสุดท้ายเพราะเซนติเมตรต่อนิ้วไม่เปลี่ยนแปลง

หากคุณพยายามแทนที่ค่าสุดท้ายตัวแปรคือสิ่งที่มันถูกประกาศก่อน ตัวอย่างเช่น:

final String helloworld = "Hello World";
helloworld = "A String"; //helloworld still equals "Hello World"

มีข้อผิดพลาดในการคอมไพล์ที่มีลักษณะดังนี้:

local variable is accessed from inner class, must be declared final

หากตัวแปรของคุณไม่สามารถประกาศขั้นสุดท้ายได้หรือหากคุณไม่ต้องการประกาศให้ลองทำดังนี้:

final String[] helloworld = new String[1];
helloworld[0] = "Hello World!";
System.out.println(helloworld[0]);
helloworld[0] = "A String";
System.out.println(helloworld[0]);

สิ่งนี้จะพิมพ์:

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