บทวิเคราะห์ Lambda Expression ปลอมของ Java เปรียบเทียบกับภาษา Kotlin
ตั้งแต่ Java 8 ถูกปล่อยออกมา จนถึงวันนี้ Java 9, Java 10 ก็ออกกันแบบรัวๆ และยังมี Java 11 ที่บอกว่าจะเป็น LTS (Long-Term Support) มาจ่ออยู่อีก ถึงแม้ว่า Java จะเป็นภาษาอันดับ 1 (*อ้างอิงข้อมูลด้านล่าง) แต่ปัจจุบันภาษาใหม่ ๆ ก็ได้รับความนิยมอย่างรวดเร็ว ทำให้ Java ต้องพยายามปรับตัว และทำตัวลู่เข้าสู่ Functional Language อย่างที่หลายๆ ภาษาเป็น
Lambda Expression เป็นหนึ่งใน syntax ที่ได้รับความนิยมสูง แต่สำหรับ Java เพิ่งมาใน Java 8 และสร้างความสับสนให้เหล่า Java Developer เจ้าเก่าพอสมควร ซึ่งผมเองก็เคยเขียนบล็อกไว้บ้าง (เขียน Lambda และใช้ syntax ใหม่ ๆ, ทำความเข้าใจให้มากขึ้นกับ Lambda Expression)
การใช้งาน Lambda ใน Java นั้นมีเงื่อนไขอยู่ (ใช้งาน Lambda กับ Class ของเราเอง) ซึ่งตั้งแต่ Java 8 ก็ได้เตรียม interface ที่ตรงตามเงื่อนไขดังกล่าวไว้ให้จำนวนหนึ่งที่ java.util.function.* เวลาเราเรียกก็เขียนด้วย lambda expression ได้เลย
ตัวอย่างนี้ผมพยายามทำให้เห็นว่า หน้าตา Lambda Receiver มันแปลกๆ ไหม ในใจเราอาจคิดว่าเราสามารถรับ parameter เป็น function ได้จริง แต่ร้บมาแล้วต้องมา call .apply() ต่ออีก นอกจากจะมี interface ใน java.util.function.* หลายตัวแล้ว แต่ละตัวก็ยังมีชื่อ method แตกต่างกันไปอีก อ้อ จำนวน parameter ก็ด้วยนะ เหอๆ sentiment_very_dissatisfied
Kotlin เป็นภาษาใหม่ที่มีรากฐานมาจาก Java ที่สำคัญยังอาศัย JDK ในการทำงาน เพราะฉะนั้นแล้วทุกอย่างใน Java จะถูกส่งต่อมายัง Kotlin ความแตกต่างหลักๆ คือเรื่อง syntax ที่เพิ่มความเป็น functional language เข้าไป
จะเห็นว่า จริง ๆ แล้ว Lambda Expression กับ Lambda Receiver เป็นสิ่งคู่กัน แต่ Java เลือกที่จะนำเสนอแค่ Lambda Expression เพียงอย่างเดียว ดีหรือไม่ดีผมก็ไม่แน่ใจ แต่ภาษาอื่นเขาไปกันไกลแล้วววว ฮ่าๆ
Lambda Expression เป็นหนึ่งใน syntax ที่ได้รับความนิยมสูง แต่สำหรับ Java เพิ่งมาใน Java 8 และสร้างความสับสนให้เหล่า Java Developer เจ้าเก่าพอสมควร ซึ่งผมเองก็เคยเขียนบล็อกไว้บ้าง (เขียน Lambda และใช้ syntax ใหม่ ๆ, ทำความเข้าใจให้มากขึ้นกับ Lambda Expression)
Higher-Order Function
เป็นคุณสมบัติอย่างหนึ่งของ funtional language คือ ฟังก์ชันที่สามารถรับ parameter เป็นฟังก์ชันได้ หรือถ้าจะเรียกให้เข้าใจง่ายขึ้นมันก็คือ "Lambda Receiver" เพราะเวลาเรียกฟังก์ชันเพื่อใช้งาน เราสามารถส่ง lambda expression มาได้นั่นเอง จะเห็นว่าใน Java 8 ถึง Java 10 นั้นก็ยังไม่มี syntax ส่วนนี้โผล่มาให้ได้เขียนกันแล้วรับ parameter เป็นฟังก์ชันได้ไงล่ะ ?
import java.util.function.Function; // ... public static void main(String[] args) { System.out.println(higherOrder(param -> param + 100)); } static String higherOrder(Function<Integer, Integer> f) { return "This is result of f(1) : " + f.apply(1); } //output :: This is result of f(1) : 101
การใช้งาน Lambda ใน Java นั้นมีเงื่อนไขอยู่ (ใช้งาน Lambda กับ Class ของเราเอง) ซึ่งตั้งแต่ Java 8 ก็ได้เตรียม interface ที่ตรงตามเงื่อนไขดังกล่าวไว้ให้จำนวนหนึ่งที่ java.util.function.* เวลาเราเรียกก็เขียนด้วย lambda expression ได้เลย
ตัวอย่างนี้ผมพยายามทำให้เห็นว่า หน้าตา Lambda Receiver มันแปลกๆ ไหม ในใจเราอาจคิดว่าเราสามารถรับ parameter เป็น function ได้จริง แต่ร้บมาแล้วต้องมา call .apply() ต่ออีก นอกจากจะมี interface ใน java.util.function.* หลายตัวแล้ว แต่ละตัวก็ยังมีชื่อ method แตกต่างกันไปอีก อ้อ จำนวน parameter ก็ด้วยนะ เหอๆ sentiment_very_dissatisfied
ตรงนี้แหละที่ผมเรียกว่า "Lambda ปลอม"
แต่มันก็ทำให้รู้ว่า ความสมบูรณ์แบบเกิดขึ้นมาได้อย่างไร
ลองมาดูโค้ดเดียวกันกับด้านบนในภาษา Kotlin กัน
fun main(args: Array) { println(higherOrder { param -> param + 100 }) } fun higherOrder(f: (Int) -> Int): String { return "This is result of f(1) : " + f(1) } //output :: This is result of f(1) : 101
จะเห็นว่า จริง ๆ แล้ว Lambda Expression กับ Lambda Receiver เป็นสิ่งคู่กัน แต่ Java เลือกที่จะนำเสนอแค่ Lambda Expression เพียงอย่างเดียว ดีหรือไม่ดีผมก็ไม่แน่ใจ แต่ภาษาอื่นเขาไปกันไกลแล้วววว ฮ่าๆ
ทดสอบ Decompile เป็น Java
นอกจากนี้ผมได้ลองเขียน Lambda Expression หลายๆ แบบ ในภาษา Kotlin และทำการ Decompile ให้เป็นภาษา Java (ด้วย IntelliJ) ผลที่ได้ก็ใกล้เคียงกับตัวอย่างด้านบน ผมขอแยกเป็นข้อสังเกตดังนี้- ถึงแม้เราจะเขียน Lambda Receiver (ที่ไม่มีใน Java) ตัวภาษา Kotlin ได้แอบเพิ่ม interface Function ของตัวเองไว้รอแล้ว เมื่อเรา decompile มาก็จะเห็นการใช้งาน interface ดังกล่าว
- การใช้งาน callback ตรงนี้ decompile ออกมาได้ไม่สมบูรณ์ แต่ถ้าเขียนกันจริง ๆ ระหว่าง Java กับ Kolin ก็ไม่ได้ต่างกันมากนัก
- foreach ตรงนี้น่าสนใจว่า เมื่อ decompile ออกมา เรากลับได้ while มาแทน foreach ของ Java 8
- ลองติดตามตัวอย่างได้ที่ Gist เลยครับ