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:
- Menangani runtime error
- Recover dari panic
- 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
Basic Panic
- Runtime error
- Stack trace
- Program termination
Recover
- Catch panic
- Return to normal flow
- Cleanup operations
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