บทนำ: จากพื้นฐานสู่ 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 มาก
