การอ้างอิงวิธีการใน Java

1. ภาพรวม

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

อ้างอิงวิธีที่เป็นชนิดพิเศษของการแสดงออกแลมบ์ดา มักใช้เพื่อสร้างนิพจน์แลมบ์ดาอย่างง่ายโดยอ้างอิงวิธีการที่มีอยู่

การอ้างอิงวิธีการมีสี่ประเภท:

  • วิธีการคงที่
  • วิธีการอินสแตนซ์ของออบเจ็กต์เฉพาะ
  • วิธีการอินสแตนซ์ของออบเจ็กต์ที่กำหนดเองประเภทใดประเภทหนึ่ง
  • ตัวสร้าง

ในบทช่วยสอนนี้เราจะสำรวจการอ้างอิงเมธอดใน Java

2. อ้างอิงถึงวิธีการแบบคงที่

เราจะเริ่มต้นด้วยตัวอย่างง่ายๆการใช้ตัวพิมพ์ใหญ่และการพิมพ์รายการสตริง :

List messages = Arrays.asList("hello", "baeldung", "readers!");

เราสามารถบรรลุสิ่งนี้ได้โดยใช้ประโยชน์จากนิพจน์แลมบ์ดาอย่างง่ายที่เรียกเมธอดStringUtils.capitalize ()โดยตรง:

messages.forEach(word -> StringUtils.capitalize(word));

หรือเราสามารถใช้การอ้างอิงวิธีการเพื่ออ้างถึงวิธีการแบบคงที่เป็นตัวพิมพ์ใหญ่ :

messages.forEach(StringUtils::capitalize);

สังเกตว่าการอ้างอิงเมธอดจะใช้ตัวดำเนินการ::เสมอ

3. การอ้างอิงถึงวิธีการอินสแตนซ์ของวัตถุเฉพาะ

เพื่อแสดงการอ้างอิงประเภทนี้ลองพิจารณาสองคลาส:

public class Bicycle { private String brand; private Integer frameSize; // standard constructor, getters and setters } public class BicycleComparator implements Comparator { @Override public int compare(Bicycle a, Bicycle b) { return a.getFrameSize().compareTo(b.getFrameSize()); } }

และสร้างวัตถุBicycleComparatorเพื่อเปรียบเทียบขนาดเฟรมจักรยาน:

BicycleComparator bikeFrameSizeComparator = new BicycleComparator();

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

createBicyclesList().stream() .sorted((a, b) -> bikeFrameSizeComparator.compare(a, b));

แต่เราสามารถใช้การอ้างอิงเมธอดเพื่อให้คอมไพเลอร์จัดการพารามิเตอร์ส่งผ่านให้เรา:

createBicyclesList().stream() .sorted(bikeFrameSizeComparator::compare);

การอ้างอิงวิธีการนั้นสะอาดกว่าและอ่านง่ายกว่ามากเนื่องจากโค้ดแสดงความตั้งใจของเราอย่างชัดเจน

4. การอ้างอิงถึงวิธีการอินสแตนซ์ของวัตถุโดยพลการของประเภทเฉพาะ

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

มาสร้างรายการจำนวนเต็มที่เราต้องการจัดเรียง:

List numbers = Arrays.asList(5, 3, 50, 24, 40, 2, 9, 18);

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

numbers.stream() .sorted((a, b) -> a.compareTo(b)); numbers.stream() .sorted(Integer::compareTo);

แม้ว่าจะยังคงเป็นซับเดียว แต่การอ้างอิงวิธีการนั้นอ่านและเข้าใจได้ง่ายกว่ามาก

5. การอ้างอิงถึงตัวสร้าง

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

มาสร้างอาร์เรย์จักรยานจากรายการสตริงด้วยแบรนด์ต่างๆ:

List bikeBrands = Arrays.asList("Giant", "Scott", "Trek", "GT");

ขั้นแรกเราจะเพิ่มตัวสร้างใหม่ในคลาสBicycleของเรา:

public Bicycle(String brand) { this.brand = brand; this.frameSize = 0; } 

ต่อไปเราจะใช้ตัวสร้างใหม่ของเราจากการอ้างอิงวิธีการและสร้างอาร์เรย์จักรยานจากรายการสตริงเดิม:

bikeBrands.stream() .map(Bicycle::new) .toArray(Bicycle[]::new); 

สังเกตว่าเราเรียกทั้งตัวสร้างBicycleและArrayโดยใช้การอ้างอิงวิธีการทำให้โค้ดของเราดูกระชับและชัดเจนมากขึ้น

6. ตัวอย่างและข้อ จำกัด เพิ่มเติม

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

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

ลองดูตัวอย่างข้อ จำกัด นี้:

createBicyclesList().forEach(b -> System.out.printf( "Bike brand is '%s' and frame size is '%d'%n", b.getBrand(), b.getFrameSize()));

กรณีง่ายๆนี้ไม่สามารถแสดงด้วยการอ้างอิงเมธอดได้เนื่องจากเมธอดprintfต้องการพารามิเตอร์ 3 ตัวในกรณีของเราและการใช้createBicyclesList () forEach ()จะอนุญาตให้การอ้างอิงเมธอดอนุมานพารามิเตอร์เดียวเท่านั้น ( อ็อบเจกต์Bicycle )

สุดท้ายเรามาดูวิธีสร้างฟังก์ชัน no-operation ที่สามารถอ้างอิงได้จากนิพจน์แลมบ์ดา

ในกรณีนี้เราต้องการใช้นิพจน์แลมบ์ดาโดยไม่ต้องใช้พารามิเตอร์

ขั้นแรกให้สร้างเมธอดdoNothingAtAll :

private static  void doNothingAtAll(Object... o) { }

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

ตอนนี้เรามาดูการใช้งานจริง:

createBicyclesList() .forEach((o) -> MethodReferenceExamples.doNothingAtAll(o)); 

7. สรุป

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

โค้ดทั้งหมดที่นำเสนอในบทความนี้มีอยู่บน GitHub