แลมบ์ดานิพจน์มีประโยชน์นอกเหนือจากการบันทึกบรรทัดของโค้ดหรือไม่


120

แลมบ์ดานิพจน์มีประโยชน์นอกเหนือจากการบันทึกบรรทัดของโค้ดหรือไม่

lambdas มีคุณสมบัติพิเศษใดบ้างที่ช่วยแก้ปัญหาที่แก้ได้ไม่ยาก? การใช้งานทั่วไปที่ฉันเห็นคือแทนที่จะเขียนสิ่งนี้:

Comparator<Developer> byName = new Comparator<Developer>() {
  @Override
  public int compare(Developer o1, Developer o2) {
    return o1.getName().compareTo(o2.getName());
  }
};

เราสามารถใช้นิพจน์แลมบ์ดาเพื่อย่อโค้ด:

Comparator<Developer> byName =
(Developer o1, Developer o2) -> o1.getName().compareTo(o2.getName());

27
โปรดทราบว่ามันอาจจะสั้นกว่านี้: (o1, o2) -> o1.getName().compareTo(o2.getName())
Thorbjørn Ravn Andersen

88
หรือสั้นกว่านั้น:Comparator.comparing(Developer::getName)
Thomas Kläger

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

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

คำตอบ:


116

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

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

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

นอกจากนี้โครงสร้างnew Type() { … }ยังรับประกันว่าจะสร้างอินสแตนซ์ใหม่ที่แตกต่างออกไป (เช่นnewเคย) อินสแตนซ์คลาสภายในที่ไม่ระบุชื่อมักจะอ้างอิงถึงอินสแตนซ์ภายนอกเสมอหากสร้างในstaticบริบทที่ไม่ใช่ ในทางตรงกันข้ามนิพจน์แลมบ์ดาจะจับเฉพาะการอ้างอิงthisเมื่อจำเป็นเท่านั้นกล่าวคือหากพวกเขาเข้าถึงthisหรือไม่ใช่staticสมาชิก และสร้างอินสแตนซ์ของข้อมูลประจำตัวที่ไม่ได้ระบุโดยเจตนาซึ่งช่วยให้การนำไปใช้งานสามารถตัดสินใจได้ที่รันไทม์ว่าจะใช้อินสแตนซ์ที่มีอยู่ซ้ำหรือไม่ (โปรดดูที่“ นิพจน์แลมบ์ดาสร้างอ็อบเจกต์บนฮีปทุกครั้งที่เรียกใช้งานหรือไม่ ”)

ความแตกต่างเหล่านี้ใช้กับตัวอย่างของคุณ โครงสร้างคลาสภายในที่ไม่ระบุตัวตนของคุณจะสร้างอินสแตนซ์ใหม่เสมอและอาจจับภาพการอ้างอิงไปยังอินสแตนซ์ภายนอกในขณะที่(Developer o1, Developer o2) -> o1.getName().compareTo(o2.getName())นิพจน์แลมบ์ดาของคุณไม่ได้จับภาพซึ่งจะประเมินเป็นซิงเกิลตันในการใช้งานทั่วไป นอกจากนี้ยังไม่สร้าง.classไฟล์ในฮาร์ดไดรฟ์ของคุณ

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


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

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

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

3
@EricDuminil: สำหรับฉันแล้วความสมบูรณ์ของทัวริงเป็นทฤษฎีมากเกินไป เช่นไม่ว่า Java จะเป็น Turing สมบูรณ์หรือไม่คุณจะไม่สามารถเขียนไดรเวอร์อุปกรณ์ Windows ใน Java ได้ (หรือใน PostScript ซึ่งเป็น Turing ก็สมบูรณ์เช่นกัน) การเพิ่มคุณสมบัติให้กับ Java ที่อนุญาตให้ทำเช่นนั้นจะเปลี่ยนชุดของปัญหาที่คุณสามารถแก้ไขได้อย่างไรก็ตามจะไม่เกิดขึ้น ดังนั้นฉันจึงชอบจุดประกอบมากกว่า เนื่องจากทุกสิ่งที่คุณทำได้ถูกนำไปใช้ในคำสั่งของ CPU ที่ทำงานได้จึงไม่มีสิ่งใดที่คุณไม่สามารถทำได้ใน Assembly ซึ่งรองรับทุกคำสั่งของ CPU (เข้าใจง่ายกว่าพิธีการของเครื่องทัวริง)
Holger

2
@abelito เป็นเรื่องปกติสำหรับโครงสร้างการเขียนโปรแกรมระดับสูงทั้งหมดเพื่อให้ "การมองเห็นสิ่งที่เกิดขึ้นจริงน้อยลง" เนื่องจากเป็นข้อมูลเกี่ยวกับรายละเอียดน้อยลงให้ความสำคัญกับปัญหาการเขียนโปรแกรมจริงมากขึ้น คุณสามารถใช้เพื่อทำให้โค้ดดีขึ้นหรือแย่ลง มันเป็นเพียงเครื่องมือ ชอบคุณสมบัติการโหวต; เป็นเครื่องมือที่คุณสามารถใช้ในลักษณะที่ตั้งใจไว้เพื่อใช้ประกอบการตัดสินเกี่ยวกับคุณภาพที่แท้จริงของโพสต์ หรือคุณใช้เพื่อลงคะแนนคำตอบที่ละเอียดและสมเหตุสมผลเพียงเพราะคุณเกลียดแลมบ์ดา
Holger

52

ภาษาโปรแกรมไม่ได้มีไว้สำหรับให้เครื่องดำเนินการ

พวกเขาเป็นสำหรับโปรแกรมเมอร์ที่จะคิดใน

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

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

มันเหมือนกับโปรแกรมเมอร์ขั้นตอนที่เรียนรู้ที่จะคิดในแง่ของคลาสเมื่อพวกเขามาที่ Java: คุณเห็นพวกเขาค่อยๆย้ายจากคลาสที่มีโครงสร้างที่ได้รับการยกย่องและมีคลาส 'ตัวช่วย' ด้วยวิธีการคงที่มากมายและย้ายไปยังสิ่งที่ คล้ายกับการออกแบบ OO ที่มีเหตุผลมากขึ้น (mea culpa)

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


5
ระวังด้วยนะฉันเคยคิดว่า OOP คือทุกอย่างและจากนั้นฉันก็สับสนอย่างมากกับสถาปัตยกรรมระบบองค์ประกอบของเอนทิตี (whaddaya หมายความว่าคุณไม่มีคลาสสำหรับออบเจ็กต์เกมแต่ละประเภท?! และแต่ละออบเจ็กต์ของเกม ไม่ใช่วัตถุ OOP?!)
user253751

3
กล่าวอีกนัยหนึ่งคือการคิดใน OOP แทนที่จะคิดว่าคลาส* o f * เป็นเครื่องมืออื่น y ได้ จำกัด ความคิดของฉันในทางที่ไม่ดี
user253751

2
@immibis: มีหลายวิธีในการ“ คิดใน OOP” ดังนั้นนอกเหนือจากความผิดพลาดทั่วไปในการทำให้“ คิดใน OOP” สับสนกับ“ การคิดในชั้นเรียน” แล้วยังมีอีกหลายวิธีที่จะคิดในเชิงต่อต้านการผลิต น่าเสียดายที่สิ่งนี้เกิดขึ้นบ่อยเกินไปตั้งแต่เริ่มต้นเนื่องจากแม้แต่หนังสือและแบบฝึกหัดก็สอนคนที่ด้อยกว่าแสดงรูปแบบการต่อต้านในตัวอย่างและเผยแพร่ความคิดนั้นออกไป ความจำเป็นที่จะต้อง“ มีคลาสสำหรับแต่ละประเภท” ไม่ว่าจะเป็นเพียงตัวอย่างเดียวซึ่งขัดแย้งกับแนวคิดเรื่องนามธรรมเช่นเดียวกันดูเหมือนว่า“ OOP หมายถึงการเขียนตำนานให้มากที่สุดเท่าที่จะทำได้” เป็นต้น
โฮลเกอร์

@immibis แม้ว่าในกรณีนั้นจะไม่ได้ช่วยคุณ แต่เกร็ดเล็กเกร็ดน้อยนั้นสนับสนุนประเด็นนี้จริง ๆ : ภาษาและกระบวนทัศน์เป็นกรอบในการจัดโครงสร้างความคิดของคุณและเปลี่ยนให้เป็นการออกแบบ ในกรณีของคุณคุณวิ่งชนขอบของเฟรมเวิร์ก แต่ในอีกบริบทหนึ่งการทำเช่นนั้นอาจช่วยคุณจากการหลงเข้าไปในโคลนก้อนโตและสร้างการออกแบบที่น่าเกลียด ดังนั้นฉันถือว่า "ทุกอย่างเป็นการแลกเปลี่ยน" การรักษาผลประโยชน์ในขณะที่การหลีกเลี่ยงปัญหาในอดีตเป็นคำถามสำคัญในการตัดสินใจว่าจะสร้างภาษาอย่างไร
Leushenko

@immibis นั่นเป็นเหตุผลว่าทำไมการเรียนรู้กระบวนทัศน์ต่างๆให้ดีจึงเป็นเรื่องสำคัญ: แต่ละคนเข้าถึงคุณเกี่ยวกับความไม่เพียงพอของผู้อื่น
Jared Smith

36

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

หากไม่มีStreamไปป์ไลน์นิพจน์แลมบ์ดา (และ / หรือการอ้างอิงวิธีการ) จะอ่านได้น้อยกว่ามาก

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

List<String> names =
    people.stream()
          .filter(p -> p.getAge() > 21)
          .map(p -> p.getName())
          .sorted((n1,n2) -> n1.compareToIgnoreCase(n2))
          .collect(Collectors.toList());

มันจะเป็น:

List<String> names =
    people.stream()
          .filter(new Predicate<Person>() {
              @Override
              public boolean test(Person p) {
                  return p.getAge() > 21;
              }
          })
          .map(new Function<Person,String>() {
              @Override
              public String apply(Person p) {
                  return p.getName();
              }
          })
          .sorted(new Comparator<String>() {
              @Override
              public int compare(String n1, String n2) {
                  return n1.compareToIgnoreCase(n2);
              }
          })
          .collect(Collectors.toList());

การเขียนนี้ยากกว่าเวอร์ชันที่มีนิพจน์แลมบ์ดามากและมีโอกาสเกิดข้อผิดพลาดได้ง่ายกว่ามาก ยังเข้าใจยากกว่า

และนี่คือท่อส่งที่ค่อนข้างสั้น

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


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

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

@tobias_k ไม่มีปัญหา ผมเปลี่ยนมันเพื่อที่จะทำให้มันมีลักษณะการทำงานที่แตกต่างกันมากกว่าcompareToIgnoreCase sorted()
Eran

1
compareToIgnoreCaseยังคงเป็นตัวอย่างที่ไม่ดีเนื่องจากคุณสามารถใช้ตัวString.CASE_INSENSITIVE_ORDERเปรียบเทียบที่มีอยู่ได้ ข้อเสนอแนะของ @ tobias_k ในการเปรียบเทียบตามความยาว (หรือคุณสมบัติอื่น ๆ ที่ไม่มีตัวเปรียบเทียบในตัว) เหมาะสมกว่า เมื่อพิจารณาจากตัวอย่างโค้ด SO Q&A แลมบ์ดาสทำให้เกิดการใช้งานตัวเปรียบเทียบที่ไม่จำเป็นมากมาย ...
Holger

ฉันเป็นคนเดียวหรือเปล่าที่คิดว่าตัวอย่างที่สองเข้าใจง่ายกว่า
Clark Battle

8

การทำซ้ำภายใน

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

numbers.forEach(new Consumer<Integer>() {
    public void accept(Integer value) {
        System.out.println(value);
    }
});

ตอนนี้ด้วย Java 8 คุณสามารถทำได้ดีขึ้นและใช้คำอธิบายน้อยลงด้วย:

numbers.forEach((Integer value) -> System.out.println(value));

หรือดีกว่า

numbers.forEach(System.out::println);

พฤติกรรมเป็นข้อโต้แย้ง

เดากรณีต่อไปนี้:

public int sumAllEven(List<Integer> numbers) {
    int total = 0;

    for (int number : numbers) {
        if (number % 2 == 0) {
            total += number;
        }
    } 
    return total;
}

ด้วยอินเทอร์เฟซ Java 8 Predicateคุณสามารถทำได้ดีกว่าเช่น:

public int sumAll(List<Integer> numbers, Predicate<Integer> p) {
    int total = 0;

    for (int number : numbers) {
        if (p.test(number)) {
            total += number;
        }
    }
    return total;
}

เรียกมันว่า:

sumAll(numbers, n -> n % 2 == 0);

ที่มา: DZone - ทำไมเราต้องใช้ Lambda Expressions ใน Java


น่าจะเป็นกรณีแรกเป็นวิธีที่จะบันทึกบรรทัดของรหัสบางอย่าง แต่มันทำให้รหัสง่ายต่อการอ่าน
alseether

4
การทำซ้ำภายในเป็นคุณลักษณะของแลมบ์ดาอย่างไร? เรื่องง่ายๆก็คือ lambdas ในทางเทคนิคอย่าให้คุณทำอะไรที่คุณไม่สามารถทำได้ก่อน java-8 เป็นเพียงวิธีที่กระชับกว่าในการส่งรหัสไปรอบ ๆ
Ousmane D.

@ Aominèในกรณีนี้numbers.forEach((Integer value) -> System.out.println(value));การแสดงออกแลมบ์ดาที่ทำจากสองส่วนหนึ่งอยู่ที่ด้านซ้ายของสัญลักษณ์ลูกศร (->) ชื่อของพารามิเตอร์และหนึ่งในที่ที่เหมาะสมที่มีของร่างกาย คอมไพเลอร์จะคำนวณโดยอัตโนมัติว่านิพจน์แลมบ์ดามีลายเซ็นเดียวกันของวิธีการเดียวที่ไม่ได้ใช้งานของอินเทอร์เฟซ Consumer
พร้อมกัน

5
ฉันไม่ได้ถามว่านิพจน์แลมบ์ดาคืออะไรฉันแค่บอกว่าการวนซ้ำภายในไม่เกี่ยวข้องกับนิพจน์แลมบ์ดา
Ousmane D.

1
@ Aominèฉันเห็นประเด็นของคุณมันไม่ได้มีอะไรกับ lambdas ต่อ seแต่อย่างที่คุณชี้ให้เห็นมันเหมือนวิธีการเขียนที่สะอาดกว่า ฉันคิดว่าในแง่ของประสิทธิภาพนั้นดีพอ ๆ กับรุ่นก่อน 8
พร้อมกัน

4

มีประโยชน์มากมายของการใช้ lambdas แทนชั้นในดังต่อไปนี้:

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

  • เมื่อใช้ lambdas คุณพอใจที่จะเขียนโปรแกรมด้วยการดำเนินการรูปแบบการทำงานบนสตรีมขององค์ประกอบเช่นการแปลงแผนที่ลดลงบนคอลเลกชัน ดูjava.util.function & java.util.streamเอกสารแพคเกจ

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

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

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

    //                 v--- create the lambda locally.
    Consumer<Integer> action = (Consumer<Integer> & Serializable) it -> {/*TODO*/};

2

Lambdas เป็นเพียงน้ำตาลที่เป็นประโยคสำหรับคลาสที่ไม่ระบุชื่อ

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

หากคุณใช้ IntelliJ IDEA สามารถทำการแปลงให้คุณได้:

  • วางเคอร์เซอร์ไว้ในแลมด้า
  • กด alt / option + enter

ใส่คำอธิบายภาพที่นี่


3
... ฉันคิดว่า @StuartMarks ได้ชี้แจงเรื่อง syntactic sugar-ity (sp? gr?) ของ lambdas แล้ว? ( stackoverflow.com/a/15241404/3475600 , softwareengineering.stackexchange.com/a/181743 )
srborlongan

2

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


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

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

2

สิ่งหนึ่งที่ผมไม่เห็นกล่าวถึงเลยก็คือว่าแลมบ์ดาให้คุณกำหนดฟังก์ชั่นที่มีการใช้งาน

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


1

มีข้อดีมากมาย

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