Java Optional: หลีกเลี่ยง NullPointerException อย่างถูกต้อง

#java13 เม.ย. 2569

NullPointerException ปัญหาคลาสสิก

NullPointerException (NPE) เป็น exception ที่พบบ่อยที่สุดใน Java Optional ช่วยให้จัดการ null values ได้อย่างปลอดภัย

สร้าง Optional

import java.util.Optional;

// Optional ที่มีค่า
Optional<String> name = Optional.of("สมชาย");

// Optional ที่อาจเป็น null
Optional<String> nullable = Optional.ofNullable(null);

// Optional ว่าง
Optional<String> empty = Optional.empty();

ตรวจสอบและดึงค่า

Optional<String> opt = Optional.of("Hello");

// isPresent / isEmpty
if (opt.isPresent()) {
    System.out.println(opt.get());
}

// ifPresent
opt.ifPresent(value -> System.out.println(value));

// orElse - ค่า default
String result = opt.orElse("default");

// orElseGet - lazy evaluation
String result2 = opt.orElseGet(() -> computeDefault());

// orElseThrow
String result3 = opt.orElseThrow(() -> new RuntimeException("ไม่พบข้อมูล"));

Transformation

Optional<String> name = Optional.of("  สมชาย  ");

// map
Optional<String> trimmed = name.map(String::trim);
Optional<Integer> length = name.map(String::length);

// flatMap
Optional<User> user = findUser(1);
Optional<String> email = user.flatMap(u -> Optional.ofNullable(u.getEmail()));

// filter
Optional<String> longName = name
    .map(String::trim)
    .filter(n -> n.length() > 3);

ตัวอย่างจริง

// ก่อน Optional
public String getUserCity(int userId) {
    User user = userRepository.findById(userId);
    if (user != null) {
        Address address = user.getAddress();
        if (address != null) {
            return address.getCity();
        }
    }
    return "ไม่ทราบ";
}

// หลัง Optional
public String getUserCity(int userId) {
    return userRepository.findById(userId)
        .map(User::getAddress)
        .map(Address::getCity)
        .orElse("ไม่ทราบ");
}

Repository Pattern

public interface UserRepository {
    Optional<User> findById(int id);
    Optional<User> findByEmail(String email);
}

// Service
public User getUser(int id) {
    return userRepository.findById(id)
        .orElseThrow(() -> new UserNotFoundException("ไม่พบ user id: " + id));
}

สิ่งที่ไม่ควรทำ

// ❌ ไม่ควรใช้ Optional เป็น field
private Optional<String> name;  // ไม่ดี

// ❌ ไม่ควรใช้ Optional เป็น parameter
void process(Optional<String> name) {}  // ไม่ดี

// ✅ ใช้ Optional เป็น return type
Optional<User> findUser(int id) { ... }  // ดี

สรุป

Optional ช่วยให้โค้ดชัดเจนขึ้นว่าค่าอาจเป็น null ได้ ใช้ map, flatMap, orElse แทนการ check null ด้วย if ทำให้โค้ดกระชับและปลอดภัยขึ้นครับ