Panic and Recover

Panic adalah kondisi runtime error yang menghentikan normal flow program. Recover adalah mekanisme untuk menangkap panic dan melanjutkan eksekusi program.

Contoh Masalah

Bagaimana cara:

  1. Menangani runtime error
  2. Recover dari panic
  3. Graceful error handling

Penyelesaian

package main

import (
    "fmt"
    "log"
)

// 1. Function yang bisa panic
func divide(a, b int) int {
    if b == 0 {
        panic("pembagian dengan nol")
    }
    return a / b
}

// 2. Function dengan recover
func safeDivide(a, b int) (result int) {
    defer func() {
        if r := recover(); r != nil {
            fmt.Printf("Recovered from panic: %v\n", r)
            result = 0
        }
    }()
    
    return divide(a, b)
}

// 3. Custom error type
type CustomError struct {
    message string
    code    int
}

func (e *CustomError) Error() string {
    return fmt.Sprintf("Error %d: %s", e.code, e.message)
}

// 4. Function yang menggunakan custom error
func processData(data string) error {
    if len(data) == 0 {
        return &CustomError{
            message: "data kosong",
            code:    400,
        }
    }
    return nil
}

// 5. Nested panic dan recover
func level3() {
    fmt.Println("Level 3 start")
    panic("panic di level 3")
}

func level2() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Printf("Level 2 recovered: %v\n", r)
            panic("panic baru di level 2") // Re-panic
        }
    }()
    
    fmt.Println("Level 2 start")
    level3()
}

func level1() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Printf("Level 1 recovered: %v\n", r)
        }
    }()
    
    fmt.Println("Level 1 start")
    level2()
}

// 6. Function dengan cleanup sebelum panic
func riskyOperation(data string) {
    // Setup resources
    fmt.Println("Setting up resources")
    
    // Cleanup handler
    defer func() {
        fmt.Println("Cleaning up resources")
        if r := recover(); r != nil {
            log.Printf("Panic handled: %v\n", r)
        }
    }()

    if len(data) < 5 {
        panic("data terlalu pendek")
    }
    
    fmt.Println("Operation completed successfully")
}

func main() {
    // Contoh 1: Basic panic dan recover
    fmt.Println("Basic Panic and Recover:")
    fmt.Printf("10/2 = %d\n", safeDivide(10, 2))
    fmt.Printf("10/0 = %d\n", safeDivide(10, 0))

    // Contoh 2: Custom error handling
    fmt.Printf("\nCustom Error Handling:\n")
    if err := processData(""); err != nil {
        if customErr, ok := err.(*CustomError); ok {
            fmt.Printf("Custom error caught: %v (code: %d)\n",
                customErr.message, customErr.code)
        } else {
            fmt.Printf("Standard error: %v\n", err)
        }
    }

    // Contoh 3: Nested panic
    fmt.Printf("\nNested Panic Example:\n")
    level1()

    // Contoh 4: Cleanup dengan panic
    fmt.Printf("\nCleanup with Panic Example:\n")
    riskyOperation("abc")
    fmt.Println("After first risky operation")
    
    riskyOperation("abcdef")
    fmt.Println("After second risky operation")

    // Contoh 5: Multiple defers dengan panic
    fmt.Printf("\nMultiple Defers with Panic:\n")
    func() {
        defer fmt.Println("First defer")
        defer fmt.Println("Second defer")
        defer func() {
            if r := recover(); r != nil {
                fmt.Printf("Recovered: %v\n", r)
            }
        }()
        defer fmt.Println("Third defer")
        
        panic("test panic")
        
        fmt.Println("This won't be printed")
    }()
    fmt.Println("Program continues")
}

Penjelasan Kode

  1. Basic Panic

    • Runtime error
    • Stack trace
    • Program termination
  2. Recover

    • Catch panic
    • Return to normal flow
    • Cleanup operations
  3. Best Practices

    • Use for exceptional cases
    • Always cleanup resources
    • Proper error handling

Output

Basic Panic and Recover:
10/2 = 5
Recovered from panic: pembagian dengan nol
10/0 = 0

Custom Error Handling:
Custom error caught: data kosong (code: 400)

Nested Panic Example:
Level 1 start
Level 2 start
Level 3 start
Level 2 recovered: panic di level 3
Level 1 recovered: panic baru di level 2

Cleanup with Panic Example:
Setting up resources
Cleaning up resources
Panic handled: data terlalu pendek
After first risky operation
Setting up resources
Operation completed successfully
Cleaning up resources
After second risky operation

Multiple Defers with Panic:
Third defer
Recovered: test panic
Second defer
First defer
Program continues

Tips

  • Gunakan panic untuk fatal errors
  • Selalu recover di defer
  • Lakukan cleanup sebelum recover
  • Re-panic jika perlu
  • Dokumentasikan panic scenarios