แลมบ์ดาแสดงออกถึงสิ่งที่มากกว่าคลาสภายในที่ไม่ระบุชื่อด้วยวิธีการเดียวหรือไม่?


40

มี hype ใหม่พร้อมกับการแสดงออกแลมบ์ดาที่รอคอยมานานใน Java 8; ทุกๆ 3 วันบทความอื่นจะปรากฏพร้อมกับพวกเขาเกี่ยวกับวิธีเจ๋ง ๆ

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

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


30
เมื่อภาษาเป็นทัวริงสมบูรณ์ทุกคุณสมบัติเพิ่มสามารถในทางทฤษฎีจะอธิบายว่า "น้ำตาลประโยค"
ฟิลิปป์

34
@ ฟิลิป: นั่นมันผิด ลักษณะการกำหนดน้ำตาลซินแทคติคคือการแยกออกเป็นท้องถิ่นล้วนๆและไม่เปลี่ยนแปลงโครงสร้างระดับโลกของโปรแกรม มีคุณสมบัติมากมายที่ไม่สามารถนำไปใช้งานได้ด้วยการแปลงเฉพาะที่ ตัวอย่างเช่นหากคุณใช้ภาษาสมมุติที่เหมือนกันกับ Java แต่มีการเรียก tail ที่เหมาะสมจะไม่สามารถ desugar tail เรียกไปยัง Java "pure" โดยไม่ต้องเปลี่ยนโปรแกรมทั้งหมด
Jörg W Mittag

2
@Phippipp: น่าเสียดายที่มี upvote เพียงหนึ่งสำหรับความคิดเห็นมิฉะนั้นฉันจะ upvote ความคิดเห็นของ Joerg 1,000 ครั้ง ไม่มันผิดที่คุณสมบัติใด ๆ ที่สามารถอธิบายได้ว่าเป็นน้ำตาลทราย น้ำตาลซินแทคติคไม่ได้เพิ่มความหมายใหม่ ในความเป็นจริง AFAIK lambdas Java ที่เสนอไม่ใช่น้ำตาลเชิงไวยากรณ์สำหรับคลาสภายในที่ไม่ระบุชื่อพิเศษเนื่องจากมีความหมายต่างกัน
Giorgio

1
@Giorgio: และพวกเขามีความหมายที่แตกต่างกันอย่างไร
user102008

2
@Giorgio: ใช่ แต่การแปลงthisเป็นOuterClass.thisเป็นส่วนหนึ่งของกระบวนการลบล้างแลมบ์ดานิพจน์ในคลาสที่ไม่ระบุชื่อ
user102008

คำตอบ:


47

tl; dr:ในขณะที่น้ำตาลส่วนใหญ่เป็น syntactic syntax นั้นดีกว่าทำให้มีหลายสิ่งหลายอย่างในทางปฏิบัติที่เคยจบลงในวงเล็บปีกกาและวงเล็บที่ไม่สามารถอ่านได้

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

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

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

อ่านง่ายกว่า:

myCollection.map(new Mapper<String,String>() {
  public String map(String input) {
    return new StringBuilder(input).reverse().toString();
  }
});

หรือ:

myCollection.map(element -> new StringBuilder(element).reverse().toString());

หรือ (ใช้การจัดการวิธีการแทนแลมบ์ดา):

myCollection.map(String::toUpperCase);

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


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

7
@ m3th0dman: จริงๆแล้ว generics ไม่ได้เพิ่มความสามารถใหม่ Listสามารถจับวัตถุใด ๆ ที่List<String>สามารถ "เท่านั้น" สตริงถือ Generics เพิ่มข้อ จำกัด (และตัวเลือกในการทำให้เป็นข้อ จำกัด !) ไม่ใช่การเพิ่มพลัง ค่อนข้างทุกอย่างตั้งแต่ Java 1.1 ได้รับน้ำตาลประโยค และนั่นก็ไม่ใช่เรื่องเลวร้าย
โจอาคิมซาวเออร์

3
@ m3th0dman: อันที่จริง generics ไม่ได้เพิ่มความสามารถใหม่เพราะใน Java พวกเขาเป็นเพียงน้ำตาลประโยค A List<String>เป็นเพียงการListโยนเพื่อStringเพิ่มรอบค่าที่ส่งคืนบางส่วน อย่างไรก็ตามมันมีประโยชน์อย่างมากและทำให้ภาษามีความสะดวกมากขึ้นในการเขียนแลมบ์ดาเป็นกรณีที่คล้ายกัน
Jan Hudec

3
จริงๆแล้วมันเป็นอะไรที่มากกว่าแค่น้ำตาลทราย ฟังก์ชั่นส่วนใหญ่นั้นถูกนำไปใช้ในฐานะพลเมืองชั้นหนึ่งใน JVM ผ่านการใช้ bytecode ที่ถูกเรียกใช้ + ความก้าวหน้าที่น่าสนใจบางอย่างในระบบอนุมาน Type มันไม่ได้นำไปใช้เป็นคลาสภายในที่ไม่ระบุชื่อ
Martijn Verburg

1
@JanHudec: เอ่อพวกมันมากกว่าน้ำตาล syntactic เล็กน้อยเพราะคอมไพเลอร์ให้ความเคารพพวกเขาจริงๆ รันไทม์ไม่ได้ดูแลเกี่ยวกับพวกเขาว่าเป็นความจริง
Joachim Sauer

14

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

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


1
การเรียนรู้ว่าทุกอย่างสามารถนำไปใช้ได้ในแง่ของ lambdas นั้นเป็นคำแนะนำที่ดีและไม่ใช่ "ความลับ" ในความคิดของฉัน (อย่างไรก็ตามฉันเดาว่า "coders" ส่วนใหญ่ไม่สนใจทฤษฎี CS ที่น่าสนใจ) นั่นไม่ได้หมายความว่า lambdas นั้นพิเศษ มันหมายถึงว่า lambdas เป็นสิ่งก่อสร้างสากลประเภทหนึ่ง มีคนอื่นเช่น SKI combinators แลมบ์ดาเป็นหน่วยการสร้างพื้นฐานในกระบวนทัศน์การทำงาน แต่บางทีสิ่งอื่นอาจเป็นพื้นฐานในกระบวนทัศน์อื่น
user102008

+1 สำหรับ "การเบี่ยงเบนความสนใจแบบข้ามวง": ฉันมักจะสงสัยว่าทำไมบางภาษาเปลี่ยนไปเลียนแบบภาษายอดนิยมอื่น ๆ และทำไมโปรแกรมเมอร์จึงทนต่อมัน ฉันชอบ lambdas และใช้พวกมันเป็นจำนวนมากใน Scala, Lisp, Haskell แต่ใน Java หรือ C ++ พวกเขารู้สึกเหมือนได้ยึดติดกับภาษาในภายหลังเพราะพวกเขาได้รับความนิยมในภาษาอื่น ๆ
Giorgio

2

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


1
ทำไม downvote สิ่งที่ฉันพูดนั้นถูกต้องสมบูรณ์
user102008

สิ่งที่คุณเขียนนั้นเป็นข้อเสนอที่สมเหตุสมผลสำหรับแลมบ์ดาของ Java แต่ข้อเสนอนี้ได้ถูกยกเลิกไปแล้วสำหรับข้อเสนอที่แตกต่าง ( doanduyhai.wordpress.com/2012/07/12/… )
Giorgio

1
@ จอร์โจ: ฉันไม่ได้ "เสนอ" อะไร อะไรที่คุณไม่เห็นด้วยกับสิ่งที่ฉันพูด? ใช่ภายในของการแสดงออกจะมีลักษณะที่แตกต่างกันเช่นเราจะเพิ่มวิธีการและใช่จะต้องมีการแปลงเป็นthis OuterClass.thisนั่นไม่ได้ขัดแย้งกับสิ่งที่ฉันพูด - การแสดงออกแลมบ์ดาทุกครั้งสามารถถูกแปลงเป็นนิพจน์คลาสแบบนิรนามที่เทียบเท่ากันโดยไม่มีการเปลี่ยนแปลงอะไรเลยนอกการแสดงออกนั้น ฉันไม่ได้บอกว่าข้างในจะไม่เปลี่ยนแปลง
user102008

3
สิ่งที่คุณพูดไม่ถูกต้อง ความหมายของแลมบ์ดาและอานนท์ชั้นในนั้นไม่เหมือนกันทุกประการ (แม้ว่าจะคล้ายกัน) จากด้านบนของหัวของฉันความหมายของความหมายของการเปลี่ยนแปลงนี้ ; และการเรียนภายในอานนท์เสมอส่งผลในตัวอย่างใหม่ของวัตถุในขณะที่แลมบ์ดาอาจมีหรือไม่
Stuart Marks

1
@ StuartMarks: ไม่คุณไม่ได้อ่านคำตอบของฉัน ฉันไม่ได้บอกว่าแต่ละคนสามารถทำทุกอย่างที่ทำได้ ฉันบอกว่าแลมบ์ดามีคลาสนิรนามที่เทียบเท่าซึ่งมีความหมายแบบเดียวกัน ดังที่ฉันได้กล่าวไปแล้วthisในคอมเม้นต์แลมบ์ดาเป็นส่วนหนึ่งของวากยสัมพันธ์น้ำตาลและไม่ได้มีความแตกต่างในความหมาย และเกี่ยวกับความแตกต่างในการนำไปใช้งานการนำไปใช้! = ความหมาย เกี่ยวกับความแตกต่างในตัวตนของวัตถุ ตัวตนของวัตถุนั้นมีความสัมพันธ์กับการใช้งานของ lambdas มาก ไม่มีใครตรวจสอบเอกลักษณ์วัตถุของคลาส lambdas / anon เพราะมันไม่มีประโยชน์
user102008

1

โจอาคิมซาวเออร์ทำหน้าที่ได้ดีในการตอบคำถามของคุณแล้ว แต่บอกเพียงบางสิ่งที่ฉันคิดว่าสำคัญ เนื่องจากแลมบ์ดาไม่มีชั้นเรียนพวกเขาจึงไม่ได้รวบรวมเช่นนี้ คลาสภายในที่ไม่ระบุชื่อทั้งหมดส่งผลให้เกิดการสร้างไฟล์. class ซึ่งจะต้องโหลดโดย ClassLoader ดังนั้นการใช้แลมบ์ดาไม่เพียง แต่ทำให้โค้ดของคุณสวยงามยิ่งขึ้น แต่ยังลดขนาดของรหัสที่คอมไพล์ของคุณรอยเท้าหน่วยความจำของ ClassLoader ของคุณและเวลาที่ใช้ในการถ่ายโอนบิตจากฮาร์ดไดรฟ์ของคุณ


-1

ไม่พวกเขาไม่ได้เป็น.

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


1
ฟังก์ชั่นการเขียนโปรแกรมสามารถตั้งฉากกับการเขียนโปรแกรมเชิงวัตถุ (ดู: Scala และ F #) สิ่งนี้อ่านเหมือนความเห็นของใครบางคนที่ไม่ชอบการเขียนโปรแกรมการทำงานตามหลักการ
KChaloux

1
@KChaloux - ไม่ใช่ผู้เขียนโปรแกรมเกลียด คำตอบนั้นเขียนโดยคนที่ต้องการมีค้อนและไขควงมากกว่าเป็น Hammerdriver การเขียนโปรแกรม OO เป็นกระบวนทัศน์ที่ดีเช่นเดียวกับการเขียนโปรแกรมการทำงาน การตั้งค่าของฉันในภาษาเพื่อให้ชัดเจนเกี่ยวกับความตั้งใจของมัน แลมบ์ดาฉันรู้สึกสกปรกธรรมชาติของ OO ของ Java Java ไม่ได้ถูกออกแบบมาให้ใช้งานได้ มนุษย์ต้องการโครงสร้างเพื่อทำงานให้ดีที่สุด
Guido Anselmi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.