การอนุมานประเภทใน Java 8


30

การแนะนำสัญกรณ์แลมบ์ดาใหม่ (ดูตัวอย่างเช่นบทความนี้ ) ใน Java 8 จะต้องใช้การอนุมานบางประเภทหรือไม่?

ถ้าเป็นเช่นนั้นระบบประเภทใหม่จะส่งผลกระทบต่อภาษาจาวาโดยรวมอย่างไร

คำตอบ:


47

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

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

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

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

ประเภทใดก็ตามที่อนุมานโดยการอนุมานประเภทสามารถเขียนออกมาได้อย่างชัดเจน ในการใช้ตัวอย่างของเฟืองล้อเฟือง

Collections.<MyClass>sort(list, (a, b) -> { return a.order - b.order; });

เป็นน้ำตาลสำหรับ

Collections.<MyClass>sort(list,
    (Comparator<MyClass>)((MyClass a, MyClass b) -> { return a.order - b.order; }));

ดังนั้นการอนุมานของข้อความ " sparkleshy " จึงไม่ต้องการส่วนขยายของระบบประเภท "จึงถูกต้อง

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

นิพจน์แลมบ์ดามีความแตกต่างทางความหมายจากคลาสภายในและมีการใช้งานแตกต่างจากคลาสภายใน

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

public class CaptureThis {
    void a(Runnable r) { r.run(); }

    void b() {
        a(new Runnable() { public void run() { System.out.println(this); }});
        a(() -> System.out.println(this));
    }

    public String toString() { return "outer"; }

    public static void main(String[] args) { new CaptureThis().b(); }
}

ในแลมบ์ดา JDK 8 รุ่นล่าสุด (ฉันใช้b69 ) ผลลัพธ์จะเป็นดังนี้:

CaptureThis$1@113de03
outer

นอกจากนี้แลมบ์ดานิพจน์ยังมีการใช้งานที่แตกต่างจากคลาสภายในอย่างสิ้นเชิง หากคุณเปรียบเทียบเอาท์พุทแยกส่วนคุณจะเห็นว่าโค้ดคลาสภายในตรงไปตรงมากับการสร้างและเรียกไปที่ตัวสร้างของ CaptureThis $ 1 ในขณะที่นิพจน์แลมบ์ดาจะคอมไพล์กับคำสั่งแบบอุทธรณ์ สำหรับคำอธิบายเต็มรูปแบบของวิธีการทำงานนี้และทำไมดูไบรอันเก๊' JavaOne 2012 พูดคุยแลมบ์ดา: แอบมองใต้กระโปรง


2
"พวกมันจับสิ่งนี้ต่างกันในชั้นในนี่คืออินสแตนซ์ของชั้นในขณะที่ในแลมบ์ดานี่เป็นตัวอย่างที่ปิดล้อมลองพิจารณาสิ่งต่อไปนี้:" ยังสามารถทำได้ด้วยน้ำตาล syntactic โดยแทนที่ทั้งหมดthisด้วยMyClass.this
ratchet freak

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

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

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

3
@ จอร์โจ: เกี่ยวกับสาเหตุที่แลมบ์ดาไม่ได้เป็นเพียงแค่วากยสัมพันธ์น้ำตาลสำหรับชั้นในที่ไม่ระบุชื่อปรากฏว่ามีการพูดคุยกันอย่างกว้างขวางเกี่ยวกับเรื่องนี้ จดหมายจากไบรอันเก๊นี้จะสรุปการตัดสินใจ: mail.openjdk.java.net/pipermail/lambda-dev/2011-August/... TL; DR เปิดประตูทิ้งไว้สำหรับวิวัฒนาการในอนาคตและเราจะได้รับประสิทธิภาพที่ดีขึ้นในวันนี้ Goetz ตอบคำถามที่เกี่ยวข้องกับวัตถุ lambdas จริงหรือ? แต่ถ้าคำตอบคือไม่หรืออาจจะแปลว่าพวกเขาไม่สามารถเป็นน้ำตาลสำหรับชั้นใน
Stuart Marks
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.