วิธีการเสริมใน Java Interface


120

จากความเข้าใจของฉันถ้าคุณใช้อินเทอร์เฟซใน java เมธอดที่ระบุในอินเทอร์เฟซนั้นจะต้องถูกใช้โดยคลาสย่อยที่ใช้อินเทอร์เฟซดังกล่าว

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


คุณอ้างถึงวิธีการใด ฉันไม่พบใน JavaDoc หรือซอร์สโค้ด
dcpomero


คำตอบ:


233

ดูเหมือนจะมีความสับสนอย่างมากในคำตอบที่นี่

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

สิ่งสำคัญคือต้องตระหนักว่ามีสองระดับที่สอดคล้องกับอินเทอร์เฟซ:

  1. สิ่งที่ภาษา Java สามารถตรวจสอบได้ นี้สวยมากเพียงเดือดลงไป: มีบางการดำเนินงานสำหรับแต่ละวิธีการหรือไม่

  2. ปฏิบัติตามสัญญาจริง. นั่นคือการนำไปใช้งานทำตามที่เอกสารในอินเทอร์เฟซแจ้งว่าควรหรือไม่

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

เมื่อออกแบบ Collections API Joshua Bloch ตัดสินใจว่าแทนที่จะมีอินเทอร์เฟซที่ละเอียดมากเพื่อแยกความแตกต่างระหว่างคอลเลกชันที่แตกต่างกัน (เช่น: อ่านได้เขียนได้เข้าถึงโดยสุ่ม ฯลฯ ) เขาจะมีเพียงชุดอินเทอร์เฟซที่หยาบมากเท่านั้น Collection, List, SetและMapแล้วเอกสารดำเนินการบางอย่างเป็น "ตัวเลือก" นี่คือเพื่อหลีกเลี่ยงการระเบิดของคอมบิเนเตอร์ที่เป็นผลมาจากอินเทอร์เฟซที่ละเอียด จากคำถามที่พบบ่อยเกี่ยวกับการออกแบบ Java Collections API :

เพื่ออธิบายปัญหาในรายละเอียดที่เต็มไปด้วยเลือดสมมติว่าคุณต้องการเพิ่มแนวคิดเรื่องการปรับเปลี่ยนลำดับชั้น คุณต้องมีอินเทอร์เฟซใหม่สี่แบบ ได้แก่ ModifiableCollection, ModifiableSet, ModifiableList และ ModifiableMap สิ่งที่เคยเป็นลำดับชั้นอย่างง่ายตอนนี้คือลำดับชั้นที่ยุ่งเหยิง นอกจากนี้คุณต้องมีอินเทอร์เฟซ Iterator ใหม่เพื่อใช้กับคอลเล็กชันที่ไม่สามารถแก้ไขได้ซึ่งไม่มีการดำเนินการลบ ตอนนี้คุณสามารถใช้ UnsupportedOperationException ได้หรือไม่? แต่น่าเสียดายที่ไม่ได้.

พิจารณาอาร์เรย์ พวกเขาใช้การดำเนินการรายการส่วนใหญ่ แต่ไม่ลบและเพิ่ม เป็นรายการ "ขนาดคงที่" หากคุณต้องการจับแนวคิดนี้ในลำดับชั้นคุณต้องเพิ่มสองอินเทอร์เฟซใหม่: VariableSizeList และ VariableSizeMap คุณไม่จำเป็นต้องเพิ่ม VariableSizeCollection และ VariableSizeSet ​​เพราะจะเหมือนกับ ModifiableCollection และ ModifiableSet แต่คุณอาจเลือกที่จะเพิ่มเพื่อความสอดคล้องกัน นอกจากนี้คุณต้องมี ListIterator ใหม่ ๆ ที่ไม่รองรับการเพิ่มและลบการดำเนินการเพื่อไปพร้อมกับรายการที่ไม่สามารถแก้ไขได้ ตอนนี้เรามีอินเทอร์เฟซมากถึงสิบหรือสิบสองอินเทอร์เฟซพร้อมด้วยอินเทอร์เฟซ Iterator ใหม่สองรายการแทนที่จะเป็นอินเทอร์เฟซเดิมสี่รายการ เราทำเสร็จหรือยัง? เลขที่

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

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

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

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

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

โปรดทราบว่าเพราะUnsupportedOperationExceptionเป็นRuntimeExceptionคุณสามารถโยนได้จากการดำเนินการวิธีการใด ๆ เท่าที่เป็นคอมไพเลอร์เป็นห่วง ตัวอย่างเช่นคุณสามารถโยนมันออกจากการใช้งานCollection.size()ไฟล์. อย่างไรก็ตามการดำเนินการดังกล่าวจะละเมิดสัญญาเนื่องจากเอกสารประกอบCollection.size()ไม่ได้ระบุว่าได้รับอนุญาต

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


30
+1 สำหรับThere are no exceptions to this rule. สงสัยว่าทำไมคำตอบนี้ไม่ถูกทำเครื่องหมายว่ายอมรับ คนอื่นดี แต่คุณให้มากเกินพอแล้ว
xyz

9
"ภาษา Java กำหนดให้ทุกวิธีในอินเทอร์เฟซถูกนำไปใช้โดยการใช้งานอินเทอร์เฟซนั้นทุกครั้งช่วงเวลาไม่มีข้อยกเว้นสำหรับกฎนี้" ยกเว้น ... เมื่อมี. :-) อินเทอร์เฟซ Java 8 สามารถระบุการใช้งานเมธอดเริ่มต้นได้ดังนั้นใน Java 8 ... จึงไม่เป็นความจริงที่ทุกวิธีในอินเทอร์เฟซจะต้องได้รับการดำเนินการโดยการใช้งานอินเทอร์เฟซทุกครั้งอย่างน้อยก็ไม่ใช่ในแง่ที่คุณต้อง รหัสการใช้งานในคลาส conrete
DaBlick

1
@DaBlick เมื่อฉันพูดว่า "ถูกนำไปใช้โดยทุกการใช้งาน" ฉันไม่ได้หมายความว่าการใช้วิธีการดังกล่าวจะต้องอยู่ในแหล่งที่มาของคลาสการใช้งาน แม้กระทั่งก่อน Java 8 เราสามารถสืบทอดการใช้งานวิธีอินเทอร์เฟซได้แม้จะมาจากคลาสที่ไม่ได้ใช้อินเทอร์เฟซดังกล่าวก็ตาม เช่นสร้างFooที่ไม่ได้ดำเนินการด้วยวิธีการของประชาชนRunnable void run()ตอนนี้สร้างชั้นBarที่extends Fooและimplements Runnableโดยไม่ต้อง runoveriding มันยังคงใช้วิธีนี้แม้ว่าจะเป็นทางอ้อม ในทำนองเดียวกันการใช้งานวิธีการเริ่มต้นยังคงเป็นการใช้งาน
ลอเรนซ์ Gonsalves

ขอโทษ. ฉันไม่ได้พยายามที่จะวิพากษ์วิจารณ์อย่างอวดดีมากเท่าที่จะดึงดูดความสนใจไปที่คุณสมบัติ Java 8 ซึ่งอาจเกี่ยวข้องกับโพสต์ต้นฉบับ ใน Java 8 ตอนนี้คุณมีตัวเลือกในการใช้งานที่ไม่ได้เข้ารหัสในระดับซุปเปอร์คลาสหรือคลาสย่อยใด ๆ สิ่งนี้ (IMHO) เปิดโลกใหม่ของรูปแบบการออกแบบรวมถึงรูปแบบบางอย่างที่อาจเหมาะสมในกรณีที่ข้อห้ามในการสืบทอดหลายมรดกอาจนำเสนอความท้าทายบางประการ ฉันคิดว่านี่จะทำให้เกิดชุดรูปแบบการออกแบบที่มีประโยชน์สูงชุดใหม่ \
DaBlick

3
@AndrewS เนื่องจากใน Java 8 removeได้รับการใช้งานเริ่มต้น หากคุณไม่นำไปใช้ชั้นเรียนของคุณจะได้รับการติดตั้งเริ่มต้น อีกสองวิธีที่คุณกล่าวถึงไม่มีการใช้งานเริ่มต้น
ลอเรนซ์ Gonsalves

27

ในการรวบรวมคลาสการนำไปใช้งาน (ไม่ใช่นามธรรม) สำหรับอินเทอร์เฟซต้องใช้วิธีการทั้งหมด

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

"ทางเลือก" ในคอลเลกชันหมายความว่าคลาสการใช้งานไม่จำเป็นต้อง 'ใช้งาน' (ตามคำศัพท์ด้านบน) มันก็จะโยน NotSupportedException)

ตัวอย่างที่ดี - add()วิธีการสำหรับคอลเลกชันที่ไม่เปลี่ยนรูป - คอนกรีตจะใช้วิธีการที่ไม่ทำอะไรเลยนอกจากการขว้างปาNotSupportedException

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


ปรับปรุง:

ตั้งแต่ java 8 วิธีเริ่มต้นถูกนำมาใช้

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

โปรดทราบว่าเมธอดยังคงใช้งานโดยคลาสทั้งหมดที่ประกาศ แต่ใช้นิยามของอินเทอร์เฟซ


แทนที่จะ "ไม่ยุ่ง" ฉันคิดว่า "มันเป็นอย่างนั้น" มากกว่า

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

12
"ไม่จำเป็นต้องใช้มัน (อาจเป็นเพียงการสร้างวิธีการที่พ่น ... )" นั่นคือการนำวิธีการ
Marquis of Lorne

1
เนื่องจากน่าเสียดายที่นี่เป็นคำตอบที่ได้รับการยอมรับฉันจึงขอแนะนำให้เขียนใหม่ ' โดยปกติการใช้งานคลาสควร (และจะ) ใช้วิธีการทั้งหมด' นั้นทำให้เข้าใจผิดตามที่EJPได้ชี้ให้เห็นแล้ว
Alberto

2
"ทางเลือก" ในคอลเลกชันหมายความว่าคลาสการนำไปใช้งานไม่จำเป็นต้องใช้มัน "- นี่เป็นเท็จธรรมดาโดย" ไม่จำเป็นต้องใช้งาน "คุณหมายถึงอย่างอื่น
djechlin

19

อินเทอร์เฟซใน Java เพียงแค่ประกาศสัญญาสำหรับการนำคลาสไปใช้งาน ต้องใช้วิธีการทั้งหมดในอินเทอร์เฟซนั้น แต่คลาสที่นำไปใช้นั้นมีอิสระที่จะปล่อยให้ไม่ได้ใช้งาน ได้แก่ เว้นว่างไว้ ดังตัวอย่างที่สร้างไว้

interface Foo {
  void doSomething();
  void doSomethingElse();
}

class MyClass implements Foo {
  public void doSomething() {
     /* All of my code goes here */
  }

  public void doSomethingElse() {
    // I leave this unimplemented
  }
}

ตอนนี้ฉันไม่ได้doSomethingElse()ใช้งานแล้วปล่อยให้คลาสย่อยของฉันใช้งานได้ฟรี นั่นเป็นทางเลือก

class SubClass extends MyClass {
    @Override
    public void doSomethingElse() {
      // Here's my implementation. 
    }
}

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


ฉันสามารถจูบคุณเพื่อนของฉัน
ไมโคร

16

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

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


ฉันไม่เคยเข้าใจจริงๆว่า Javadocs หมายถึงอะไรโดยทางเลือก ฉันเชื่อว่าพวกเขาหมายถึงอย่างที่คุณพูด แต่วิธีการส่วนใหญ่เป็นทางเลือกตามมาตรฐานnew Runnable ( ) { @ Override public void run ( ) { throw new UnsupportedOperationException ( ) ; } }นั้น: ;
emory

ดูเหมือนจะใช้ไม่ได้กับวิธีการที่เป็นทางเลือกแต่ตัวอย่างเช่นadd((T)null)อาจใช้ได้ในกรณีหนึ่ง แต่ไม่ใช่วิธีอื่น นั่นคือการพูดคุยเกี่ยวกับข้อยกเว้นตัวเลือก / พฤติกรรมและสำหรับอาร์กิวเมนต์ ( "ข้อ จำกัด ในองค์ประกอบ" ... "องค์ประกอบที่ไม่เหมาะสม" ... "ข้อยกเว้นการทำเครื่องหมายเป็นตัวเลือก") และไม่ได้อยู่ที่วิธีการที่ไม่จำเป็น

9

ต้องใช้วิธีการทั้งหมดเพื่อให้โค้ดคอมไพล์ (นอกเหนือจากdefaultวิธีการใช้งานใน Java 8+) แต่การนำไปใช้งานไม่จำเป็นต้องทำอะไรที่เป็นประโยชน์ โดยเฉพาะมัน:

  • อาจว่างเปล่า (วิธีการว่างเปล่า)
  • อาจแค่โยนUnsupportedOperationException(หรือคล้ายกัน)

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


5

อันที่จริงฉันได้รับแรงบันดาลใจจาก SurfaceView.Callback2 ฉันคิดว่านี่เป็นวิธีที่เป็นทางการ

public class Foo {
    public interface Callback {
        public void requiredMethod1();
        public void requiredMethod2();
    }

    public interface CallbackExtended extends Callback {
        public void optionalMethod1();
        public void optionalMethod2();
    }

    private Callback mCallback;
}

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

ขออภัยภาษาอังกฤษห่วย


5

ใน Java 8 และใหม่กว่าคำตอบสำหรับคำถามนี้ยังคงใช้ได้ แต่ตอนนี้มีความเหมาะสมมากขึ้น

ประการแรกข้อความเหล่านี้จากคำตอบที่ยอมรับยังคงถูกต้อง:

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

แล้วความแตกต่างที่แปลกใหม่ใน Java 8 คืออะไร? เมื่อพูดถึง"วิธีการเสริม"ใดสิ่งหนึ่งต่อไปนี้เป็นสิ่งที่เหมาะสม:

1. วิธีการที่มีการใช้งานเป็นทางเลือกตามสัญญา

"คำสั่งที่สาม" กล่าวว่าต้องใช้วิธีการอินเทอร์เฟซนามธรรมเสมอและยังคงเป็นจริงใน Java 8+ อย่างไรก็ตามเช่นเดียวกับใน Java Collections Framework คุณสามารถอธิบายวิธีการอินเทอร์เฟซนามธรรมบางอย่างเป็น "ทางเลือก" ในสัญญาได้

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

public SomeReturnType optionalInterfaceMethodA(...) {
    throw new UnsupportedOperationException();
}

ใน Java 7 และรุ่นก่อนหน้านี้เป็น "เมธอดทางเลือก" ชนิดเดียวที่มีกล่าวคือเมธอดที่หากไม่ได้ใช้งานจะโยน UnsupportedOperationException ลักษณะการทำงานนี้จำเป็นต้องระบุโดยสัญญาอินเทอร์เฟซ (เช่นวิธีการเชื่อมต่อที่เป็นทางเลือกของ Java Collections Framework)

2. วิธีการเริ่มต้นที่มีการนำไปใช้ใหม่เป็นทางเลือก

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

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

ในสภาพแวดล้อมใหม่นี้ Java Collections Framework สามารถเขียนใหม่เป็น:

public interface List<E> {
    :
    :
    default public boolean add(E element) {
        throw new UnsupportedOperationException();
    }
    :
    :
}

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

ในกรณีนี้ "คำสั่งที่สาม" ข้างต้นยังคงเป็นจริงเนื่องจากวิธีนี้ถูกนำไปใช้ในอินเทอร์เฟซ

3. วิธีการที่ส่งกลับOptionalผลลัพธ์

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

ในรูปแบบการเขียนโปรแกรมที่คล่องแคล่วเช่นชนิดที่พบเห็นได้ทั่วไปเมื่อเขียนโค้ดด้วย Java Streams API ใหม่ผลลัพธ์ที่เป็นค่าว่าง ณ จุดใดก็ได้ทำให้โปรแกรมหยุดทำงานด้วย NullPointerException Optionalระดับให้กลไกสำหรับการกลับมาผล null รหัสลูกค้าในวิธีที่ช่วยให้รูปแบบได้อย่างคล่องแคล่วโดยไม่ก่อให้รหัสลูกค้าที่จะผิดพลาด


4

หากเราอ่านโค้ดAbstractCollection.javaใน grepCode ซึ่งเป็นคลาสบรรพบุรุษสำหรับการใช้งานคอลเลกชันทั้งหมดจะช่วยให้เราเข้าใจความหมายของวิธีการทางเลือก นี่คือรหัสสำหรับวิธีการเพิ่ม (e) ในคลาส AbstractCollection วิธีการเพิ่ม (e) เป็นทางเลือกตามอินเทอร์เฟซการรวบรวม

public boolean  add(E e) {

        throw new UnsupportedOperationException();
    } 

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


4

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

ดังนั้นเราจึงบอกว่าเราต้องการให้ออบเจ็กต์ประเภทนั้นอย่างน้อยตระหนักถึง "onClose ()" แต่อีกอันเป็นทางเลือก

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

ดังนั้นหากคุณต้องการตระหนักด้วยวิธีนี้ก็จะมีลักษณะดังต่อไปนี้

public interface Closer {
    default void doFirst() {
        System.out.print("first ... ");
    }
    void onClose();
    default void doLast() {
        System.out.println("and finally!");
    }
}

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

public class TestCloser implements Closer {
    @Override
    public void onClose() {
        System.out.print("closing ... ");
    }
}

ด้วยเอาต์พุต:

first ... closing ... and finally!

หรือ

public class TestCloser implements Closer {
    @Override
    public void onClose() {
        System.out.print("closing ... ");
    }

    @Override
    public void doLast() {
        System.out.println("done!");
    }
}

ด้วยผลลัพธ์:

first ... closing ... done!

ชุดค่าผสมทั้งหมดเป็นไปได้ สิ่งใดก็ตามที่มี "ค่าเริ่มต้น" สามารถนำไปใช้งานได้ แต่ต้องไม่ใช่อย่างไรก็ตามสิ่งใดก็ตามที่ไม่ต้องดำเนินการ

หวังว่าคงไม่ผิดที่ฉันตอบตอนนี้

ขอให้ทุกคนมีวันที่ดี!

[แก้ไข 1]: โปรดทราบ: ใช้ได้เฉพาะใน Java 8


ใช่ขอโทษฉันลืมพูดถึงเรื่องนี้ ... ควรแก้ไขเดี๋ยวนี้
Thorben Kuck

1

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

ดังนั้นแทนที่จะใช้อินเทอร์เฟซฉันใช้คลาสที่มีการใช้งานว่างเปล่าเช่น:

public class MyCallBack{
    public void didResponseCameBack(String response){}
}

และคุณสามารถตั้งค่าตัวแปรสมาชิก CallBack ได้เช่นนี้

c.setCallBack(new MyCallBack() {
    public void didResponseCameBack(String response) {
        //your implementation here
    }
});

แล้วเรียกแบบนี้

if(mMyCallBack != null) {
    mMyCallBack.didResponseCameBack(response);
}

ด้วยวิธีนี้คุณจะไม่ต้องกังวลกับการใช้งานทุกวิธีต่อการโทรกลับ แต่จะแทนที่เฉพาะวิธีที่คุณต้องการเท่านั้น


0

แม้ว่ามันจะไม่ตอบคำถามของ OP ก็เป็นที่น่าสังเกตว่าเป็นของ Java 8 เพิ่มวิธีการเริ่มต้นเพื่อการเชื่อมต่อในความเป็นจริงไปได้ defaultคำหลักที่วางไว้ในลายเซ็นวิธีอินเตอร์เฟซที่จะส่งผลในชั้นเรียนที่มีตัวเลือกที่จะแทนที่วิธี แต่ไม่จำเป็นต้องใช้มัน


0

บทช่วยสอน Java Collections ของ Oracle:

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

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