Lambda Expression & Functional Interface

บทนำ: จากพื้นฐานสู่ Lambda

เมื่อเขียนโปรแกรม บ่อยครั้งต้องสร้าง interface เพื่อใช้กับ event listeners หรือ callbacks:

text❌ ปัญหา: Anonymous Inner Class ยาวเกิน
├─ ต้องเขียนหลายบรรทัด
├─ เฉพาะแค่ implement method เดียว
├─ Code ดูยุ่งและซ้ำซ้อน
└─ ยากต่อการอ่าน

✓ วิธีแก้: Lambda Expression (Java 8+)
├─ Syntax ที่ concise
├─ อ่านง่าย ชัดเจน
├─ Shorter code
└─ Functional programming support

Lambda Expression = Shorthand syntax สำหรับ anonymous functions ที่ implement functional interface

Functional Interface = Interface ที่มี single abstract method เพียงตัวเดียว


Functional Interface: ก่อนจะใช้ Lambda

คำอธิบาย

java// ✓ Functional Interface - มี single abstract method
@FunctionalInterface
public interface Calculator {
    int calculate(int a, int b);  // ← เมธอดเดียว
}

// ✓ Functional Interface - Predicate
@FunctionalInterface
public interface Checker {
    boolean check(String value);  // ← เมธอดเดียว
}

// ✓ Functional Interface - Processor
@FunctionalInterface
public interface DataProcessor {
    void process(String data);  // ← เมธอดเดียว
}

// ❌ ไม่ใช่ Functional Interface - มี 2 abstract methods
@FunctionalInterface  // ← error!
public interface Invalid {
    int method1();
    void method2();
}

// ✓ ANNOTATION @FunctionalInterface
// - บ่งชี้ว่า interface นี้เป็น functional interface
// - Compiler จะ check ว่ามี single abstract method เท่านั้น
// - Optional แต่ recommended ใช้

ตัวอย่าง: Functional Interface ที่ใช้บ่อยใน Java

java// ✓ Built-in Functional Interfaces in java.util.function

// 1. Runnable - ไม่มี parameter, ไม่มี return
@FunctionalInterface
public interface Runnable {
    void run();
}

// 2. Callable<T> - ไม่มี parameter, มี return
@FunctionalInterface
public interface Callable<T> {
    T call() throws Exception;
}

// 3. Consumer<T> - มี parameter, ไม่มี return
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

// 4. Supplier<T> - ไม่มี parameter, มี return
@FunctionalInterface
public interface Supplier<T> {
    T get();
}

// 5. Function<T, R> - มี parameter, มี return
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

// 6. Predicate<T> - มี parameter, return boolean
@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}

ตัวอย่างที่ 1: Anonymous vs Lambda

❌ ก่อนจะมี Lambda: Anonymous Inner Class

java// ❌ Anonymous inner class - ยาวและซ้ำซ้อน

// Interface
interface Calculator {
    int calculate(int a, int b);
}

// Usage - Anonymous inner class
public class Main {
    public static void main(String[] args) {
        
        // Add operation
        Calculator add = new Calculator() {
            @Override
            public int calculate(int a, int b) {
                return a + b;
            }
        };
        System.out.println("Add: " + add.calculate(5, 3));  // 8
        
        // Multiply operation
        Calculator multiply = new Calculator() {
            @Override
            public int calculate(int a, int b) {
                return a * b;
            }
        };
        System.out.println("Multiply: " + multiply.calculate(5, 3));  // 15
    }
}

// ❌ PROBLEMS:
// - 4-5 บรรทัด สำหรับ logic เพียง 1 บรรทัด
// - ยุ่ง ยากอ่าน
// - Boilerplate code เยอะ

✓ ใช้ Lambda Expression

java// ✓ Lambda - concise และ elegant

@FunctionalInterface
interface Calculator {
    int calculate(int a, int b);
}

public class Main {
    public static void main(String[] args) {
        
        // Add operation - lambda
        Calculator add = (a, b) -> a + b;
        System.out.println("Add: " + add.calculate(5, 3));  // 8
        
        // Multiply operation - lambda
        Calculator multiply = (a, b) -> a * b;
        System.out.println("Multiply: " + multiply.calculate(5, 3));  // 15
        
        // Divide operation - lambda
        Calculator divide = (a, b) -> a / b;
        System.out.println("Divide: " + divide.calculate(10, 2));  // 5
    }
}

// ✓ BENEFITS:
// - 1 บรรทัด สำหรับ logic
// - ชัดเจน readable
// - ไม่มี boilerplate

Lambda Syntax Breakdown

textLambda Expression Syntax:

(parameters) -> expression
(parameters) -> { statements; }

ตัวอย่าง:

1. No parameters
   () -> "Hello"
   () -> System.out.println("Hi");

2. One parameter
   x -> x * 2
   name -> System.out.println("Hi " + name);

3. Multiple parameters
   (a, b) -> a + b
   (x, y) -> { System.out.println(x + y); return x + y; }

4. Type declaration (optional)
   (int a, int b) -> a + b
   (String s) -> s.length()

Diagram:

(a, b) -> a + b
 ↑     ↑  ↑
 |     |  └─ Expression/Body
 |     └──── Arrow (->)
 └────────── Parameters

ตัวอย่างที่ 2: Lambda with Different Signatures

ตัวอย่างต่างๆ ของ Lambda

java// 1. Lambda returning void
@FunctionalInterface
interface Printer {
    void print(String message);
}

// Usage
Printer printer = message -> System.out.println(message);
printer.print("Hello World");  // Output: Hello World

// 2. Lambda returning boolean
@FunctionalInterface
interface Validator {
    boolean isValid(String email);
}

// Usage
Validator emailValidator = email -> email.contains("@");
System.out.println(emailValidator.isValid("[email protected]"));  // true
System.out.println(emailValidator.isValid("invalid"));  // false

// 3. Lambda with multiple statements
@FunctionalInterface
interface Greeter {
    void greet(String name, int count);
}

// Usage
Greeter greeter = (name, count) -> {
    for (int i = 0; i < count; i++) {
        System.out.println("Hello, " + name);
    }
};
greeter.greet("Alice", 3);
// Output:
// Hello, Alice
// Hello, Alice
// Hello, Alice

// 4. Lambda with type declaration
@FunctionalInterface
interface Converter {
    String convert(int number);
}

// Usage
Converter toHex = (int num) -> Integer.toHexString(num);
System.out.println(toHex.convert(255));  // ff

// 5. Lambda with local variable
@FunctionalInterface
interface Multiplier {
    int multiply(int a, int b);
}

// Usage
int factor = 10;
Multiplier multiplier = (a, b) -> {
    int result = a * b * factor;
    return result;
};
System.out.println(multiplier.multiply(2, 3));  // 60

ตัวอย่างที่ 3: Real-World Lambda Usage

Sorting with Lambda

java// ✓ Sorting list ด้วย lambda

public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Charlie", "Alice", "Bob");
        
        // ❌ Before: Anonymous class
        // Collections.sort(names, new Comparator<String>() {
        //     @Override
        //     public int compare(String a, String b) {
        //         return a.compareTo(b);
        //     }
        // });
        
        // ✓ With Lambda
        Collections.sort(names, (a, b) -> a.compareTo(b));
        System.out.println(names);  // [Alice, Bob, Charlie]
        
        // ✓ Descending order
        Collections.sort(names, (a, b) -> b.compareTo(a));
        System.out.println(names);  // [Charlie, Bob, Alice]
    }
}

Thread Creation with Lambda

java// ✓ Creating threads ด้วย lambda

public class Main {
    public static void main(String[] args) {
        
        // ❌ Before: Anonymous class
        // Thread thread = new Thread(new Runnable() {
        //     @Override
        //     public void run() {
        //         System.out.println("Thread running");
        //     }
        // });
        
        // ✓ With Lambda
        Thread thread = new Thread(() -> {
            System.out.println("Thread running");
            try {
                Thread.sleep(1000);
                System.out.println("Thread finished");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        
        thread.start();
    }
}

Event Handling with Lambda

java// ✓ Button click handler ด้วย lambda

public class ButtonApp {
    
    private JButton saveButton;
    private JButton cancelButton;
    
    public void setupUI() {
        
        // ❌ Before: Anonymous class
        // saveButton.addActionListener(new ActionListener() {
        //     @Override
        //     public void actionPerformed(ActionEvent e) {
        //         saveData();
        //     }
        // });
        
        // ✓ With Lambda
        saveButton.addActionListener(
            event -> saveData()
        );
        
        // Cancel button
        cancelButton.addActionListener(
            event -> closeWindow()
        );
    }
    
    private void saveData() {
        System.out.println("Saving data...");
    }
    
    private void closeWindow() {
        System.out.println("Closing window...");
    }
}

Filtering Data with Lambda

java// ✓ Filtering list ด้วย lambda

public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        
        // Filter: Even numbers
        List<Integer> evenNumbers = new ArrayList<>();
        for (Integer num : numbers) {
            if (num % 2 == 0) {
                evenNumbers.add(num);
            }
        }
        System.out.println("Even numbers: " + evenNumbers);
        
        // ✓ With lambda (ตัวอย่าง - ต้องใช้ Stream ในหน่วยเรียนถัดไป)
        List<Integer> evens = filter(
            numbers, 
            n -> n % 2 == 0  // ← Lambda: Predicate
        );
        System.out.println("Evens: " + evens);
    }
    
    // Helper method
    static List<Integer> filter(List<Integer> list, Predicate<Integer> predicate) {
        List<Integer> result = new ArrayList<>();
        for (Integer num : list) {
            if (predicate.test(num)) {
                result.add(num);
            }
        }
        return result;
    }
}

// ✓ Predicate interface
@FunctionalInterface
interface Predicate<T> {
    boolean test(T t);
}

ตัวอย่างที่ 4: Creating Functional Interface

Custom Functional Interface

java// ✓ Custom functional interfaces

// Interface 1: Processing data
@FunctionalInterface
public interface DataProcessor {
    String process(String data);
    
    // default method (allowed in functional interface)
    default void log(String message) {
        System.out.println("LOG: " + message);
    }
}

// Interface 2: Operation
@FunctionalInterface
public interface Operation {
    double execute(double x, double y);
}

// Interface 3: Converter
@FunctionalInterface
public interface TypeConverter<T, R> {
    R convert(T value);
}

// Usage
public class Main {
    public static void main(String[] args) {
        
        // 1. DataProcessor lambda
        DataProcessor uppercase = text -> text.toUpperCase();
        System.out.println(uppercase.process("hello"));  // HELLO
        uppercase.log("Processing complete");
        
        // 2. Operation lambda
        Operation add = (x, y) -> x + y;
        Operation multiply = (x, y) -> x * y;
        System.out.println("Add: " + add.execute(10, 5));  // 15
        System.out.println("Multiply: " + multiply.execute(10, 5));  // 50
        
        // 3. TypeConverter lambda
        TypeConverter<String, Integer> stringToInt = 
            text -> Integer.parseInt(text);
        System.out.println(stringToInt.convert("123"));  // 123
        
        TypeConverter<Integer, String> intToString = 
            num -> "Number: " + num;
        System.out.println(intToString.convert(456));  // Number: 456
    }
}

Lambda vs Anonymous Class: Comparison Table

ตารางเปรียบเทียบ

text┌─────────────────┬──────────────────┬──────────────────┐
│ ลักษณะ           │ Anonymous Class  │ Lambda           │
├─────────────────┼──────────────────┼──────────────────┤
│ Syntax          │ ยาว (4-5 บรรทัด) │ สั้น (1 บรรทัด) │
│ Readability     │ ยุ่ง             │ ชัดเจน           │
│ Interface       │ Any interface    │ Functional only  │
│ Instance        │ สร้าง object ใหม่ │ No new object   │
│ this reference  │ refer to class   │ refer to outer  │
│ Scope variable  │ ไม่ต้อง final    │ ต้อง effectively │
│ Performance     │ เร็ว             │ เร็ว            │
│ java Version    │ ตั้งแต่ Java 1.1  │ Java 8+         │
└─────────────────┴──────────────────┴──────────────────┘

Lambda Expression Rules

Important Rules

text┌──────────────────────────────────────┐
│ LAMBDA EXPRESSION RULES              │
├──────────────────────────────────────┤
│                                      │
│ 1. SINGLE ABSTRACT METHOD ONLY       │
│    - Interface ต้อง functional       │
│    - Exactly one abstract method     │
│    - Can have default/static methods │
│                                      │
│ 2. TYPE INFERENCE                    │
│    - Compiler ปกติ infer types       │
│    - Can be explicit (optional)      │
│    - (int a) -> a + 1  (explicit)    │
│    - (a) -> a + 1  (inferred)        │
│                                      │
│ 3. PARAMETER SYNTAX                  │
│    - No params: ()                   │
│    - One param: x (no parens)        │
│    - One param explicit: (int x)     │
│    - Multi params: (a, b)            │
│    - All types must match            │
│                                      │
│ 4. BODY SYNTAX                       │
│    - Single expression: -> expr      │
│    - Multiple statements: -> { }     │
│    - Return statement required if    │
│      using braces and return type    │
│                                      │
│ 5. LOCAL VARIABLE ACCESS             │
│    - Can access outer variables      │
│    - Must be effectively final        │
│    - Can't modify captured variables │
│                                      │
│ 6. EXCEPTION HANDLING                │
│    - Can throw checked exceptions    │
│    - Interface must declare throws   │
│                                      │
└──────────────────────────────────────┘

Local Variable Capture

java// ✓ Effectively final variables

public class Main {
    public static void main(String[] args) {
        
        int x = 10;  // effectively final
        // x = 20;   // ❌ Not allowed - breaks effectively final
        
        Calculator calc = (a, b) -> a + b + x;
        System.out.println(calc.calculate(2, 3));  // 15 (2+3+10)
        
        // ❌ This would cause error:
        // int y = 5;
        // y = 10;  // Changed - not effectively final
        // Calculator calc2 = (a, b) -> a + b + y;  // ❌ Error
    }
}

@FunctionalInterface
interface Calculator {
    int calculate(int a, int b);
}

Best Practices: Lambda Expression

text✓ ควรใช้ Lambda เมื่อ:
  ☑ Functional interface มี single method
  ☑ Logic ง่าย (typically < 10 lines)
  ☑ Pass as argument ต่อ method
  ☑ Event handlers, callbacks
  ☑ Sorting, filtering, transforming

✓ Lambda Best Practices:
  ☑ Keep lambda concise
  ☑ Use meaningful parameter names
  ☑ Extract complex logic to method
  ☑ Avoid lambda เมื่อ logic complex
  ☑ Mark interface with @FunctionalInterface

✗ หลีกเลี่ยง:
  ☐ Lambda ที่ยาวเกิน 10 บรรทัด
  ☐ Multiple nested lambdas
  ☐ Modifying external variables
  ☐ Lambda แล้ว catch checked exception
     ที่ interface ไม่ declare
  ☐ Override static/default methods

Diagram: Lambda Expression Execution

textLambda Expression Execution Flow:

┌─────────────────────────────────┐
│  Define Lambda                  │
│  (a, b) -> a + b                │
└────────────┬────────────────────┘
             │
             ▼
┌─────────────────────────────────┐
│  Assign to Functional Interface │
│  Calculator calc = ...          │
└────────────┬────────────────────┘
             │
             ▼
┌─────────────────────────────────┐
│  Call Interface Method          │
│  calc.calculate(5, 3)           │
└────────────┬────────────────────┘
             │
             ▼
┌─────────────────────────────────┐
│  Execute Lambda Body            │
│  return a + b  (5 + 3)          │
└────────────┬────────────────────┘
             │
             ▼
┌─────────────────────────────────┐
│  Return Result                  │
│  8                              │
└─────────────────────────────────┘

สรุป

Lambda Expression & Functional Interface ทำให้ Java code สั้น เรียบง่าย และ elegant:

Key Concepts:

  • Functional Interface = Interface มี single abstract method
  • Lambda Expression = Shorthand สำหรับ functional interface
  • Syntax: (parameters) -> { body }

Advantages:

  • Concise – Code สั้นกว่า anonymous class
  • Readable – ชัดเจนว่าทำอะไร
  • Functional – Support functional programming
  • Flexible – ใช้ได้กับหลาย scenarios

Real-World Uses:

  • Event handling
  • Sorting and filtering
  • Thread creation
  • Callbacks and event listeners
  • Data transformation

Lambda expressions ไม่ใช่ feature ทั่วไป แต่เป็น game changer ใน Java programming – มัน transform Java จาก verbose language มาเป็น concise, modern language ถ้า master lambdas ได้ code จะ professional, readable และ maintainable มาก