ก่อนจะไปใช้ Lambda Expressionใน Java ต้องทำความเข้าใจกับสิ่งนี้ก่อน

Paul Story
NexaByte Dispatches
8 min readOct 28, 2023

By @NexaByte Dispatches

ทำความเข้าใจใน Interfaces ก่อน

  • *interface** คือการกำหนดกรอบงานที่ class ควรจะทำ โดยไม่ต้องบอกวิธีการทำ
  • Class ที่ต้องการใช้งานตามกรอบนั้นต้องใช้คำว่า implements
  • เมื่อคลาสมีการ implements interface แล้วจำเป็นต้องทำตามที่ interface นั้นกำหนด
  • ถ้า class ทั่วไป (ไม่ใช่ abstract) implements interface ต้องมี code สำหรับทุก method ใน interface
  • ในขณะที่ class สามารถ extend มาจาก class อื่นได้เพียงคลาสเดียว แต่ class สามารถ implement interface ได้มากกกว่า 1 interface
class Dog extends Animal implements Moveable, Loveabl
คลาส Dog นั้นเป็น : Animal, Moveable และ Loveable
  • ตั้งแต่ Java 8 เป็นต้นมา การสืบทอด method ที่เป็น concrete จาก interface สามารถทำได้แล้ว interface สามารถประกอบด้วย method ทั้งที่เป็นแบบ abstract และ concrete โดยมีการเติมเป็น default methods และ static methods ไว้หน้า method

ขยายความเมื่อพูดถึง “ method ที่เป็น concrete” ใน Interface ของ Java คือหมายถึง method ที่มีการกำหนดรายละเอียดการทำงานและสามารถเรียกใช้งานได้เลย ซึ่งใน Java 8 ขึ้นไป interfacce สามารถมี method ประเภทนี้ได้ โดยการใช้คำว่า default หน้า method

public interface ExampleInterface {
// abstract method (traditional method in interface)
void abstractMethod();

// concrete method (added in Java 8 using default keyword)
default void concreteMethod() {
System.out.println("This is a concrete method in an interface.");
}
}

ในตัวอย่างข้างต้น abstract method คือ abstract ที่ไม่มีรายละเอียดการทำงาน ในขณะที่ concrete method คือ concrete ที่มีรายละเอียดการทำงานและสามารถเรียกใช้งานได้เลย

  • Class ที่ทำการ implement interface ไม่จำเป็นต้อง implement static method หรือ default method ที่อยู่ใน interface
  • Default method ใน interface สามารถถูกสืบทอดมายัง class ที่ทำการ implement interface นั้น แต่ static method ใน interface ไม่สามารถถูกสืบทอดมายัง class ที่ทำการ implement interface นั้นได้
public interface MyInterface {

// 1. Default method
default void defaultMethod() {
System.out.println("This is a default method in an interface.");
}

// 2. Static method
static void staticMethod() {
System.out.println("This is a static method in an interface.");
}

// 3. Abstract method
void abstractMethod();
}

public class MyClass implements MyInterface {

// class นี้จำเป็นต้อง implement เฉพาะ abstract method จาก MyInterface
@Override
public void abstractMethod() {
System.out.println("This is an implemented abstract method from MyInterface.");
}
}

public class Main {
public static void main(String[] args) {
MyClass obj = new MyClass();

obj.abstractMethod(); // Output: This is an implemented abstract method from MyInterface.
obj.defaultMethod(); // Output: This is a default method in an interface.

// เราไม่สามารถเรียก static method ผ่าน object ได้ แต่เรียกผ่านชื่ออินเตอร์เฟซได้
MyInterface.staticMethod(); // Output: This is a static method in an interface.
}
}
  • **interface** เองนั้นมีลักษณะเป็น “abstract” โดยปริยายหมายความว่าเราไม่สามารถสร้าง instance ของ interface ได้ และ method ภายใน interface (ถ้าไม่ได้ระบุเป็น default หรือ static) มันจะเป็น abstract เสมอ
  • เมื่อเราเขียน “public abstract interface I {}” ก็จะมีความหมายเหมือนกับการเขียน “public interface I” การระบุคำว่า “abstract” กับ interface เป็นการซ้ำซ้อนเพราะ interface เป็น abstract อยู่แล้ว
  • สำหรับ interface ที่เป็น “top-level” (หมายถึง interface ที่ไม่ได้ถูกประกาศภายในคลาสอื่น) สามารถมีระดับการเข้าถึงเป็น public หรือ package-private การระบุเป็น private หรือ protected จะไม่ถูกต้องสำหรับ interface top-level

ก่อนไปต่อขอขยายความคำว่า “package-private” สักหน่อย

package-private (บางครั้งเรียกว่า default access) เป็นระดับการเข้าถึงใน Java ที่ไม่ได้ระบุแบบเฉพาะเจาะจง โดยการไม่ใส่ modifier ใด ๆ หน้า variable, method หรือ class สิ่งที่จะเกิดขึ้นคือ variable, method หรือ class นั้นจะสามารถเข้าถึงได้จากคลาสอื่น ๆ ที่อยู่ใน package เดียวกันเท่านั้น แต่ไม่สามารถเข้าถึงจากคลาสที่อยู่ใน package อื่น ๆ ได้ ตามตัวอย่างข้างล่าง

package com.example;

class PackagePrivateClass {
String defaultAccessVariable = "I can be accessed only within the com.example package";

void defaultAccessMethod() {
System.out.println("This method can be accessed only within the com.example package");
}
}

ต่อครับ นี้คือตัวอย่าง interface top-level กับ ที่ไม่ใช่ top level

// ในไฟล์ชื่อ MyInterface.java ภายใน package myPackage
package myPackage;

// นี่คือ top-level interface
public interface MyInterface {

// method แบบ abstract ซึ่งเป็นลักษณะเริ่มต้นของ method ใน interface
void myAbstractMethod();

// method แบบ default ซึ่งถูกเพิ่มเข้ามาใน Java 8
default void myDefaultMethod() {
System.out.println("This is a default method in MyInterface.");
}

// method แบบ static ซึ่งก็ถูกเพิ่มเข้ามาใน Java 8
static void myStaticMethod() {
System.out.println("This is a static method in MyInterface.");
}
}

เปรียบเทียบกับ interface ที่ไม่ใช่ top level

public class OuterClass {

// นี่คือ nested (inner) interface ภายใน OuterClass
public interface NestedInterface {
void nestedMethod();
}

// class ภายในที่ implement nested interface
public class InnerClass implements NestedInterface {
@Override
public void nestedMethod() {
System.out.println("Implementing method of nested interface.");
}
}
}

public class Main {
public static void main(String[] args) {
OuterClass.NestedInterface nestedObj = new OuterClass().new InnerClass();
nestedObj.nestedMethod(); // Output: Implementing method of nested interface.
}
}
  • ทุก method ใน interface จะมีลักษณะเป็น public โดยปริยาย (implicitly)
public interface MyInterface {

// โดยปริยาย, มันเป็น "public abstract"
void myAbstractMethod();

// โดยปริยาย, มันเป็น "public"
default void myDefaultMethod() {
System.out.println("Default method.");
}

// โดยปริยาย, มันเป็น "public"
static void myStaticMethod() {
System.out.println("Static method.");
}
}

เราไม่สามารถระบุระดับการเข้าถึง (access modifier) อื่น ๆ ให้กับ method ใน interface ได้ ถ้าเราพยายามใส่ private, protected หรือ package-private สำหรับ method ใน interface ตัว complier จะแสดงข้อผิดพลาดให้เห็น

เว้นแต่ใน Java 9 ขึ้นไปมันอนุญาตให้มี private method ภายใน interface ด้วย เพื่อช่วยในการจัดการการ code ภายใน default หรือ static methods ใน interface นั้นเอง

ตัวอย่าง Java 9 ที่ให้มี private method ภายใน interface

public interface MyInterface {

default void displayGreeting() {
String greeting = getGreeting(); // ใช้ private method ภายใน method default
System.out.println(greeting);
}

default void displayFarewell() {
String farewell = getFarewell(); // ใช้ private method ภายใน method default
System.out.println(farewell);
}

// private method ภายใน interface
private String getGreeting() {
return "Hello from MyInterface!";
}

// private method ภายใน interface
private String getFarewell() {
return "Goodbye from MyInterface!";
}
}
  • ใน Java เมื่อคุณประกาศ method ภายใน interface โดยไม่มีการระบุให้เป็น default หรือ static และไม่มี method body แล้ว method นั้นจะถูกถือว่าเป็น abstract โดยอัตโนมัตินั่นหมายความว่า class ที่ implements interface นั้นจะต้องมีการ @Override และสร้าง method body สำหรับทุก abstract method ใน interface นอกเสียจาก default และ static method ที่ถูกเพิ่มเข้ามาใน Java 8 เราไม่จำเป็นต้องมีการ @Override ตามตัวอย่าง
public interface MyInterface {

// นี่ถือว่าเป็น "public abstract" โดยปริยาย
void abstractMethod();

// method แบบ default มี method body
default void defaultMethod() {
System.out.println("This is a default method.");
}

// method แบบ static มี method body
static void staticMethod() {
System.out.println("This is a static method.");
}
}
  • ทุกตัวแปร (variables) ที่ประกาศใน interface จะต้องมีลักษณะเป็น public static และ final โดยปริยาย นั่นหมายความว่าเราไม่สามารถประกาศตัวแปร instance ภายใน interface ได้ แต่เราสามารถประกาศค่าคงที่ (constants) ได้เท่านั้น ตามตัวอย่างด้านล่าง
public interface MyInterface {

// นี่ถือว่าเป็น "public static final" โดยปริยาย
int CONSTANT_VALUE = 100;
}

ในตัวอย่างข้างต้น CONSTANT_VALUE ถือว่าเป็น public static final โดยปริยาย หมายความว่าค่านี้เป็นค่าคงที่ไม่สามารถเปลี่ยนแปลงได้หลังจากถูกประกาศและเป็นสมาชิกของ interface เอง (ไม่ได้เป็นสมาชิกของ instance ของคลาสที่ implements interface)

  • ไม่สามารถสร้าง instance ของ interface ได้โดยตรง เราไม่สามารถใช้คำสั่ง new กับ interface เพื่อสร้าง object จาก interface นั้นๆ ได้ เนื่องจาก interface ไม่มี constructor
  • interface สามารถใช้เป็น reference type แม้ว่าเราจะไม่สามารถสร้าง instance ของ interface ได้โดยตรง แต่เราสามารถใช้ interface เป็นประเภทของ reference สำหรับ objects ที่เป็น instance ของคลาสที่ implements interface นั้นๆ ตามตัวอย่างด้านล่างของการ reference
interface Printable {
void print();
}

class Printer implements Printable {
@Override
public void print() {
System.out.println("Printing...");
}
}

public class Test {
public static void main(String[] args) {
Printable p = new Printer(); // ใช้ interface ของ Printable เป็นชนิดของการ reference
p.print();
}
}

ในตัวอย่างข้างต้น Printer คือคลาสที่ implements interface ของ Printable แม้ว่าเราจะไม่สามารถสร้าง instance ของ Printable ได้โดยตรง แต่เราสามารถใช้ Printable เป็นชนิดของตัวแปร p ที่อ้างอิงไปยัง object ของ Printer ที่ถูกสร้างขึ้น

ความเข้าใจต่อมา Functional Interfaces คืออะไร

**Functional interface** ถูกนำมาใน Java 8 ซึ่งสนับสนุนการใช้งาน lambda expressions คุณสมบัติพื้นฐานของ functional interface คือ

1. ต้องมีเพียง abstract method เดียวเท่านั้นภายใน interface
2. default และ static methods ภายใน interface จะไม่ถูกนับเข้าไป หมายความว่า functional interface สามารถมี default และ static methods ได้หลาย method แต่ยังคงมี abstract method เดียวเท่านั้น
3. Method ที่ถูกสืบทอดมาจากคลาส Object (เช่น toString, equals, และ hashCode) จะไม่ถูกนับเข้าไป

เรายังสามารถใช้ annotation “@FunctionalInterface” เพื่อระบุว่า interface นั้นเป็น functional interface ได้ (Annotation นี้เป็นเพียงเครื่องมือเพื่อช่วยให้ compiler ตรวจสอบว่า interface นั้นทำตามเงื่อนไขของ functional interface

ตัวอย่าง:

@FunctionalInterface
public interface MyFunctionalInterface {
void execute();

// method default
default void defaultMethod() {
System.out.println("Default method");
}

// method static
static void staticMethod() {
System.out.println("Static method");
}
}

ในตัวอย่างข้างต้น MyFunctionalInterface เป็น functional interface เนื่องจากมีเพียง abstract method เดียว (execute) และ default กับ static methods จะไม่ถูกนับเข้าไป

Method ที่เป็น lambda expressions ในตัวอย่างข้างต้นเป็นการแทนที่การใช้งาน abstract method ของแต่ละ functional interface

  1. Runnable
  • มาจาก java.lang package
  • ใช้สำหรับการแทน code block ที่ไม่มีการรับ input และไม่มีการ return ค่า output
  • มี method void run()
Runnable runnable = () -> System.out.println("Running...");
runnable.run();

2. Callable<V>

  • มาจาก java.util.concurrent package
  • คล้ายกับ Runnable แต่สามารถ return ค่า (value) ของประเภท v ได้
  • มี method V call() throws Exception
Callable<String> callable = () -> "Called!";
try {
String result = callable.call();
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}

3. Predicate<T>

  • มาจาก java.util.function package
  • ใช้สำหรับการทดสอบ object ตามเงื่อนไขที่กำหนด และ return ค่า boolean
  • มี method boolean test(T t)
Predicate<String> isNotEmpty = s -> !s.isEmpty();
System.out.println(isNotEmpty.test("Hello")); // จะแสดงค่า true
System.out.println(isNotEmpty.test("")); // จะแสดงค่า false

ความเข้าใจต่อมา Lambda Expression คืออะไร

  • Lambda expression เป็นฟีเจอร์ที่ถูกนำเข้ามาใช้ใน Java 8 และเป็นวิธีการที่ทำให้เราสามารถเขียน code ที่กระชับและเรียบง่ายขึ้น โดยเฉพาะเวลาที่เราต้องการส่ง behavior หรือการกระทำเป็น parameter ไปยัง method
  • Lambda expression สามารถใช้แทน anonymous inner class ในหลาย ๆ กรณี โดยเฉพาะเมื่อเราต้องการใช้งาน interface ที่มีเพียง method เดียว (functional interface) ตัวอย่างการใช้ anonymous inner class:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Running in the thread");
}
}).start();

ส่วนนี้เป็นตัวอย่างการใช้ lambda expression

new Thread(() -> System.out.println("Running in the thread")).start();

จะเห็นว่าการใช้ lambda expression ทำให้ code กระชับและอ่านง่ายขึ้น อีกทั้งยังช่วยลด boilerplate code ที่ไม่จำเป็นออกไป

อย่างไรก็ตาม lambda expression ไม่ได้เป็นเพียงแค่ “block of code” ที่ทำให้ code กระชับขึ้นเท่านั้น แต่ยังเป็นเครื่องมือที่มีประสิทธิภาพในการเขียน functional programming style ใน Java และช่วยในการทำงานร่วมกับ Stream API และฟีเจอร์อื่น ๆ ของ Java 8 อีกด้วย

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

Code ประเภทนี้มักทำให้การพัฒนาโปรแกรมล่าช้าลงและเพิ่มความซับซ้อนในการทำความเข้าใจ code เพิ่มขึ้นอีกด้วย

ตัวอย่างของ boilerplate code คือการเขียน getters และ setters สำหรับคลาสใน Java ถ้าคลาสมี fields จำนวนมาก เราก็ต้องเขียน method เหล่านี้ซ้ำแล้วซ้ำเล่าโดยที่โครงสร้างเป็นแบบเดียวกัน

public class Person {
private String name;
private int age;

// Boilerplate code:
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}

การมีเครื่องมือหรือฟีเจอร์ที่ช่วยลด boilerplate code เช่น Lombok สำหรับ Java หรือการใช้ annotations จะช่วยให้โปรแกรมเมอร์เขียน code ที่กระชับและสะดวกขึ้น

  • Lambda expression ใน Java ถูกออกแบบมาเพื่อทำงานร่วมกับ functional interfaces หากพูดง่าย ๆ functional interface คือ interface ที่มีเพียง method abstract เดียว (รวมทั้งถ้ามี method default, static หรือ method ที่ได้รับมาจาก object ก็ยังนับว่าเป็น functional interface เช่นกัน)
  • Lambda expression ให้เราสามารถสร้าง instance ของ functional interface โดยไม่ต้องเขียน class แบบปกติหรือ anonymous inner class แทนที่จะเขียนทั้งหมดเราสามารถใช้ lambda expression เพื่อแทนที่ method abstract นั้น ๆ ใน functional interface
// Functional interface
@FunctionalInterface
interface Greeting {
void sayHello(String name);
}

public class LambdaDemo {
public static void main(String[] args) {
// Using lambda expression to create an instance of Greeting
Greeting greeting = (name) -> System.out.println("Hello, " + name);

greeting.sayHello("Alice");
}
}

ในตัวอย่างข้างต้น Greeting เป็น functional interface ที่มี method sayHello และเราใช้ lambda expression เพื่อสร้าง instance ของ Greetingโดยไม่ต้องเขียน class เพิ่มเติม

การใช้ @FunctionalInterface annotation เพื่อตรวจสอบนั้นไม่จำเป็นสำหรับ functional interface แต่ถ้าระบุมันก็จะช่วยให้ compiler ตรวจสอบว่า interface นั้นมีเพียง method abstract เดียวซึ่งต้องตรงกับนิยามของ functional interface

  • เมื่อเราใช้ lambda expression ใน Java ภายในเครื่อง Java (JVM) จะแปลง lambda expression นั้นเป็น instance ของคลาสที่เรียกว่า “lambda proxy class” ซึ่งจะทำการ implement functional interface ที่เกี่ยวข้อง ดังนั้นเราสามารถพิจารณาว่า lambda expression เป็น “syntactic sugar” หรือการแทนที่การเขียน code ซึ่งยาวและซ้ำซ้อนด้วยรูปแบบที่กระชับและง่ายต่อการเข้าใจได้
@FunctionalInterface
interface Greeting {
void sayHello(String name);
}

public class LambdaDemo {
public static void main(String[] args) {
// Using lambda expression
Greeting greeting = (name) -> System.out.println("Hello, " + name);

greeting.sayHello("Alice");
}
}

ในตัวอย่างข้างต้น lambda expression: (name) -> System.out.println(“Hello, “+ name) ไม่ได้เป็น instance ของคลาสโดยตรง แต่ JVM จะแปลงมันให้เป็น instance ของคลาสบางคลาส (lambda proxy class) ที่ implement Greeting interface

ดังนั้นถึงแม้ว่าเราจะบอกว่า “lambda expression เป็น instance ของคลาสที่ implement functional interface” ก็ไม่ผิด แต่เราควรเข้าใจในการทำงานภายในของ JVM และสิ่งที่ Java ให้เราเห็นและใช้งาน

  • Lambda expressions ใน Java มีลักษณะเป็นรูปแบบย่อของ methods และสามารถถูกใช้เพื่อระบุส่วนของ code ที่ต้องการจะถูกเรียกใช้ อย่างไรก็ตาม lambda expressions ไม่มีชื่อและไม่ได้ถูกผูกมัดกับ class ใด ๆ ซึ่งทำให้เรียกว่า “anonymous methods” หรือ “method ที่ไม่มีชื่อ”
  • Lambda expressions จริง ๆ แล้วเป็น objects (หรือ instances) แต่ไม่มีสถานะข้อมูลหรือคุณสมบัติที่เราเห็นใน class ปกติแทนที่จะมี fields, constructors หรือ methods หลาย ๆ ตัว lambda มีเพียง behavior หนึ่ง ๆ ตามที่ระบุไว้
  • เมื่อเราใช้ lambda expression Java compiler แปลงมันเป็น instance ของคลาสภายใน (known as lambda proxy class) ที่ implements functional interface ที่เกี่ยวข้อง
Runnable r = () -> System.out.println("Running...");

ในตัวอย่างข้างต้น, lambda expression: () -> System.out.println(“Running…”) ถูกแปลงเป็น instance ของ Runnable interface แม้ว่าเราจะไม่เห็น class หรือ constructor ภายใน lambda แต่เมื่อ lambda ถูกสร้างขึ้นแล้วมันกลายเป็น object ของคลาสที่ถูกสร้างขึ้นภายใน JVM ซึ่ง implements Runnable interface

  • เมื่อเราพูดถึง functional interfaces ใน Java (interfaces ที่มีเพียง method abstract เดียว) compiler สามารถบอกเราได้จากนิยามของ interface นั้นๆ โดยเฉพาะตอนที่เราใช้ lambda expressions ดังนั้นเราไม่จำเป็นต้องระบุประเภทของพารามิเตอร์หรือคืนค่าใน lambda หาก compiler สามารถบอกเราได้จาก context
  • Lambda expressions คือการแทนที่ของการสร้าง anonymous inner class ซึ่งทำให้ code ของเรากระชับและชัดเจนยิ่งขึ้นแทนที่เราจะต้องเขียน code ที่ซับซ้อนและมี boilerplate ตัว Lambda expressions ทำให้เราสามารถระบุ behavior ของเราในรูปแบบที่ซับซ้อนน้อยลงได้
@FunctionalInterface
interface Calculator {
int operate(int a, int b);
}

public class LambdaDemo {
public static void main(String[] args) {
// Using lambda expression to define the behavior
Calculator addition = (a, b) -> a + b;
System.out.println(addition.operate(5, 3)); // Outputs: 8
}
}

ในตัวอย่างข้างต้น Calculator เป็น functional interface ที่มี method abstract operate เมื่อเรากำหนด lambda expression: (a, b) -> a + b, compiler จะสามารถสรุปได้ว่า a และ b เป็นประเภท int จากนิยามของ interface และ lambda expression นั้นจะถูกแปลงเป็น instance ของคลาสภายในที่ implement Calculator interface

นี่คือตัวอย่างการเปรียบเทียบก่อนที่จะมี lambda expression (pre-java 8 กับ java 8)

interface Calculator {
int operate(int a, int b);
}

public class PreJava8Demo {
public static void main(String[] args) {
//pre java8
Calculator addition = new Calculator() {
@Override
public int operate(int a, int b) {
return a + b;
}
};
System.out.println(addition.operate(5, 3)); // Outputs: 8

// java 8 with lambda expression
Calculator addition = (a, b) -> a + b;
System.out.println(addition.operate(5, 3)); // Outputs: 8
}

}
}

พอแค่นี้ก่อนเอาไว้ครั้งหน้า ถ้าว่างจะมาเล่าหรือแสดงให้เห็นการเขียน การใช้งาน lambda expression ใน Java กันต่อ…

แถม ”Syntactic sugar” เป็นคำศัพท์ในวงการ programming ที่ใช้อธิบายฟีเจอร์หรือการเขียน codeในภาษาโปรแกรมที่ไม่เพิ่มฟังก์ชัน ไม่เพิ่มเติมใด ๆ ให้กับโปรแกรม แต่แค่ทำให้การเขียนหรืออ่าน code ง่ายขึ้น หรือทำให้ code สวยงามและเข้าใจได้ง่ายขึ้น ความหมายของ “sugar” ในที่นี้คือ “การปรับปรุง” เพื่อทำให้ code ดูดีขึ้น โดยไม่เปลี่ยนแปลงฟังก์ชันหรือความสามารถหลักของโปรแกรม

ตัวอย่างของ syntactic sugar:

  1. For-each loop ใน Java: การใช้ for-each loop ทำให้การวนซ้ำผ่าน collection เป็นไปได้อย่างง่าย แต่ภายในจริงๆ มันก็ยังคือการใช้ iterators
    java อยู่
for (String item : listOfStrings) {
System.out.println(item);
}

2. Lambda expressions ใน Java 8+: Lambda expressions ใช้เพื่อให้การเขียน inner classes ที่มี method เดียว (เช่น สำหรับ callbacks) ง่ายขึ้น แต่ภายในเครื่องจริงๆ มันก็คือการสร้าง class เหล่านั้นอยู่

button.setOnAction(e -> System.out.println("Button clicked!"));

ทั้งนี้ “syntactic sugar” ช่วยในการทำให้ code ดูดีและเขียนได้ง่ายขึ้น แต่สิ่งที่เป็นรากเหง้าของภาษาก็ยังคงเป็นเหมือนเดิม ฟีเจอร์เหล่านี้แค่สร้างความพอใจให้กับเหล่านักพัฒนาเท่านั้น มันไม่ได้เปลี่ยนแปลงการทำงานของโปรแกรมให้ดีขึ้นเท่าไหร่

--

--