Dark mode
Error Handling (การจัดการข้อผิดพลาด)
การจัดการข้อผิดพลาดเป็นส่วนสำคัญในการเขียนโปรแกรมที่ช่วยให้แอปพลิเคชันทำงานได้อย่างมีเสถียรภาพและง่ายต่อการดีบัก
Basic Error Handling (การจัดการข้อผิดพลาดพื้นฐาน)
js
// Try-Catch-Finally
// ใช้ try-catch-finally สำหรับจัดการข้อผิดพลาด
function divide(a, b) {
try {
if (b === 0) {
throw new Error("หารด้วยศูนย์ไม่ได้");
}
return a / b;
} catch (error) {
console.error("เกิดข้อผิดพลาด:", error.message);
return null;
} finally {
console.log("ทำการคำนวณเสร็จสิ้น");
}
}
// เรียกใช้งาน
divide(10, 2); // 5
divide(10, 0); // แสดงข้อความผิดพลาด
// Promise-based error handling
async function fetchData() {
try {
const response = await fetch("https://api.example.com/data");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data);
} catch (error) {
console.error("ไม่สามารถดึงข้อมูลได้:", error);
}
}
rust
// Rust ใช้ Result และ Option สำหรับจัดการข้อผิดพลาด
fn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
return Err("หารด้วยศูนย์ไม่ได้".to_string());
}
Ok(a / b)
}
// ใช้งาน Result กับ match
match divide(10.0, 2.0) {
Ok(result) => println!("ผลลัพธ์: {}", result),
Err(e) => eprintln!("ข้อผิดพลาด: {}", e),
}
// ใช้ unwrap_or_else สำหรับค่าเริ่มต้นเมื่อเกิดข้อผิดพลาด
let result = divide(10.0, 0.0).unwrap_or_else(|e| {
eprintln!("เกิดข้อผิดพลาด: {}", e);
0.0 // ค่าเริ่มต้น
});
// Custom error type
#[derive(Debug)]
pub enum MyError {
DivisionByZero,
NegativeNumber(i32),
}
impl std::fmt::Display for MyError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
MyError::DivisionByZero => write!(f, "หารด้วยศูนย์ไม่ได้"),
MyError::NegativeNumber(n) => write!(f, "เลข {} เป็นค่าลบ", n),
}
}
}
impl std::error::Error for MyError {}
fn process_number(n: i32) -> Result<f64, MyError> {
if n < 0 {
return Err(MyError::NegativeNumber(n));
}
// การประมวลผลอื่นๆ
Ok(n as f64)
}
python
# Basic try-except
# ใช้ try-except-else-finally สำหรับจัดการข้อผิดพลาด
def divide(a: float, b: float) -> float | None:
try:
if b == 0:
raise ValueError("หารด้วยศูนย์ไม่ได้")
return a / b
except ValueError as e:
print(f"ข้อผิดพลาด: {e}")
return None
except Exception as e:
print(f"เกิดข้อผิดพลาดที่ไม่คาดคิด: {e}")
return None
else:
print("คำนวณสำเร็จ")
finally:
print("สิ้นสุดการทำงาน")
# เรียกใช้งาน
result = divide(10, 2) # 5.0
result = divide(10, 0) # แสดงข้อความผิดพลาด
# Custom exception
class ValidationError(Exception):
def __init__(self, message="ข้อมูลไม่ถูกต้อง"):
self.message = message
super().__init__(self.message)
def validate_age(age: int):
if age < 0:
raise ValidationError("อายุต้องมากกว่าหรือเท่ากับ 0")
if age > 120:
raise ValidationError("อายุต้องไม่เกิน 120 ปี")
return True
try:
validate_age(-5)
except ValidationError as e:
print(f"ตรวจสอบข้อมูลไม่ผ่าน: {e}")
go
// Go ใช้ error type และ multiple return values
// ฟังก์ชันที่อาจเกิดข้อผิดพลาดจะคืนค่า error เป็นค่าสุดท้าย
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("หารด้วยศูนย์ไม่ได้")
}
return a / b, nil
}
// เรียกใช้งาน
result, err := divide(10, 2)
if err != nil {
log.Fatalf("เกิดข้อผิดพลาด: %v", err)
}
fmt.Printf("ผลลัพธ์: %v\n", result)
// Custom error type
type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("%s: %s", e.Field, e.Message)
}
func validateAge(age int) error {
if age < 0 {
return &ValidationError{
Field: "age",
Message: "อายุต้องมากกว่าหรือเท่ากับ 0",
}
}
if age > 120 {
return &ValidationError{
Field: "age",
Message: "อายุต้องไม่เกิน 120 ปี",
}
}
return nil
}
// ใช้งาน custom error
err := validateAge(-5)
if err != nil {
if verr, ok := err.(*ValidationError); ok {
fmt.Printf("ตรวจสอบข้อมูลไม่ผ่าน: %s\n", verr)
} else {
fmt.Printf("เกิดข้อผิดพลาด: %v\n", err)
}
}
Best Practices (แนวทางที่ดีที่สุด)
- ใช้ข้อความแสดงข้อผิดพลาดที่ชัดเจน - อธิบายว่าอะไรผิดพลาดและวิธีแก้ไข
- ไม่ควรใช้ try-catch ครอบโค้ดทั้งหมด - จัดการเฉพาะส่วนที่คาดว่าจะเกิดข้อผิดพลาด
- ใช้ประเภทข้อผิดพลาดที่เหมาะสม - ใช้ built-in error types หรือสร้าง custom error types
- บันทึกข้อผิดพลาด - บันทึกลง log file หรือระบบติดตามข้อผิดพลาด
- ตรวจสอบข้อผิดพลาดทุกครั้ง - อย่าลืมตรวจสอบค่า error ที่ได้จากการเรียกฟังก์ชัน
- ใช้ finally หรือ defer สำหรับการทำความสะอาดทรัพยากร
- เอกสารข้อผิดพลาดที่อาจเกิดขึ้น - บอกผู้ใช้ว่าอาจเกิดข้อผิดพลาดอะไรได้บ้าง
ตัวอย่างการจัดการข้อผิดพลาดแบบ Asynchronous
js
async function fetchUserData(userId) {
try {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error("ไม่สามารถโหลดข้อมูลผู้ใช้ได้:", error);
throw error; // ส่งต่อข้อผิดพลาดให้ caller จัดการต่อ
}
}
rust
use reqwest;
use std::error::Error;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
match fetch_user_data(1).await {
Ok(user) => println!("ข้อมูลผู้ใช้: {:?}", user),
Err(e) => eprintln!("เกิดข้อผิดพลาด: {}", e),
}
Ok(())
}
async fn fetch_user_data(user_id: i32) -> Result<serde_json::Value, Box<dyn Error>> {
let url = format!("https://api.example.com/users/{}", user_id);
let response = reqwest::get(&url).await?;
if !response.status().is_success() {
return Err(Box::new(std::io::Error::new(
std::io::ErrorKind::Other,
format!("HTTP error! status: {}", response.status())
)));
}
let user_data = response.json::<serde_json::Value>().await?;
Ok(user_data)
}
python
import aiohttp
import asyncio
async def fetch_user_data(user_id):
try:
async with aiohttp.ClientSession() as session:
async with session.get(f'https://api.example.com/users/{user_id}') as response:
if response.status != 200:
raise Exception(f'HTTP error! status: {response.status}')
return await response.json()
except aiohttp.ClientError as e:
print(f'เกิดข้อผิดพลาดในการเชื่อมต่อ: {e}')
raise
except Exception as e:
print(f'เกิดข้อผิดพลาด: {e}')
raise
go
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"sync"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
// เพิ่มฟิลด์อื่นๆ ตามต้องการ
}
func fetchUserData(userID int, wg *sync.WaitGroup, ch chan<- *User, errCh chan<- error) {
defer wg.Done()
url := fmt.Sprintf("https://api.example.com/users/%d", userID)
resp, err := http.Get(url)
if err != nil {
errCh <- fmt.Errorf("ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์: %v", err)
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
errCh <- fmt.Errorf("HTTP error! status: %s", resp.Status)
return
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
errCh <- fmt.Errorf("ไม่สามารถอ่านข้อมูล: %v", err)
return
}
var user User
if err := json.Unmarshal(body, &user); err != nil {
errCh <- fmt.Errorf("ไม่สามารถแปลงข้อมูล JSON: %v", err)
return
}
ch <- &user
}
func main() {
userIDs := []int{1, 2, 3}
var wg sync.WaitGroup
userCh := make(chan *User, len(userIDs))
errCh := make(chan error, len(userIDs))
// เรียก goroutines เพื่อดึงข้อมูลผู้ใช้แบบขนาน
for _, id := range userIDs {
wg.Add(1)
go fetchUserData(id, &wg, userCh, errCh)
}
// รอให้ goroutines ทั้งหมดทำงานเสร็จ
go func() {
wg.Wait()
close(userCh)
close(errCh)
}()
// รับและแสดงผลลัพธ์
for user := range userCh {
fmt.Printf("ได้รับข้อมูลผู้ใช้: %+v\n", user)
}
// ตรวจสอบข้อผิดพลาด
for err := range errCh {
fmt.Printf("เกิดข้อผิดพลาด: %v\n", err)
}
}
การจัดการข้อผิดพลาดที่ดีจะช่วยให้แอปพลิเคชันของคุณมีความเสถียรและง่ายต่อการบำรุงรักษาในระยะยาว