Указатели, функции и управление выполнением в Go vs Java | Types - Language

Серия: Go для Java-разработчиков — разбираем pointer, closures, defer, panic/recover

В этой статье мы разберем, как Go управляет состоянием и жизненным циклом функций. Особенность Go — лёгкая работа с указателями без сложной арифметики, мощные функции-замыкания и встроенные механизмы для безопасного завершения и обработки ошибок. Для Java-разработчика это позволяет понять различия с привычными ссылками, исключениями и лямбдами.


Указатели (pointer) и value vs reference semantics

Указатели в Go позволяют работать с адресами переменных, но без pointer arithmetic. Это безопаснее, чем в C, и аналогично ссылкам в Java, но с явным синтаксисом.

Пример функции с pointer

// Go
func update(x *int) {
    *x = 10
}

func main() {
    a := 5
    update(&a)
    fmt.Println(a) // 10
}

Java эквивалент:

// Java
class Main {
    static void update(IntegerWrapper x) {
        x.value = 10;
    }

    public static void main(String[] args) {
        IntegerWrapper a = new IntegerWrapper(5);
        update(a);
        System.out.println(a.value); // 10
    }
}

class IntegerWrapper {
    int value;
    IntegerWrapper(int v) { value = v; }
}
Go делает явными ссылки через pointer. Value receiver работает с копией, pointer receiver — с оригиналом.

Function literal / Closure — функции как объекты

В Go функции — полноценные объекты первого класса. Замыкания (closures) позволяют сохранять состояние между вызовами.

Пример closure

// Go
func counter() func() int {
    i := 0
    return func() int {
        i++
        return i
    }
}

func main() {
    c := counter()
    fmt.Println(c()) // 1
    fmt.Println(c()) // 2
}

Java эквивалент (через лямбду с объектом)

// Java
import java.util.function.Supplier;

class Counter {
    int i = 0;
    Supplier<Integer> counter() {
        return () -> ++i;
    }

    public static void main(String[] args) {
        Counter obj = new Counter();
        Supplier<Integer> c = obj.counter();
        System.out.println(c.get()); // 1
        System.out.println(c.get()); // 2
    }
}
Closure позволяет Go хранить внутреннее состояние функции без создания отдельного класса. Это удобно для счётчиков, генераторов, callback.

Defer — отложенное выполнение (аналог try-with-resources)

Defer выполняет функцию в конце текущего блока. Это удобно для закрытия ресурсов или освобождения памяти.

Пример defer

// Go
func main() {
    defer fmt.Println("world")
    fmt.Println("hello")
}
// Output:
// hello
// world

Java эквивалент (try-with-resources / finally)

// Java
public class Main {
    public static void main(String[] args) {
        try {
            System.out.println("hello");
        } finally {
            System.out.println("world");
        }
    }
}
// Output:
// hello
// world
Defer удобен для чистого кода, особенно с файлами, сокетами и другими ресурсами.

Panic / Recover — обработка критических ошибок

В Go panic — это аналог unchecked exceptions в Java, но более контролируемый. Recover позволяет перехватывать панику и продолжать выполнение.

Пример panic/recover

// Go
func safeDivide(a, b int) (result int) {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered:", r)
            result = 0
        }
    }()
    if b == 0 {
        panic("division by zero")
    }
    return a / b
}

func main() {
    fmt.Println(safeDivide(10, 0)) // Recovered: division by zero \n 0
}

Java эквивалент

// Java
public class Main {
    static int safeDivide(int a, int b) {
        try {
            return a / b;
        } catch (ArithmeticException e) {
            System.out.println("Recovered: " + e.getMessage());
            return 0;
        }
    }

    public static void main(String[] args) {
        System.out.println(safeDivide(10, 0));
    }
}
Panic и recover позволяют аккуратно обработать критические ошибки, не ломая весь поток выполнения.

Сравнение key concepts Go ↔ Java

Концепция Go Java Комментарий
Указатели explicit pointer, no arithmetic ссылки на объекты Go делает ссылку явной
Value vs reference semantics value receiver / pointer receiver primitive vs object reference Pointer receiver изменяет оригинал
Closure function literal, captures vars lambda / anonymous class Можно хранить состояние функции
Defer отложенное выполнение try-with-resources / finally Удобно для освобождения ресурсов
Panic / Recover runtime error / catch unchecked exception / try-catch Перехват критических ошибок

Практический вывод

Для Java-разработчика, изучающего Go, важно понимать:

  • Указатели в Go — безопасные и явные, без арифметики
  • Value vs pointer receiver позволяет контролировать изменения данных
  • Функции — объекты первого класса, closure хранят состояние
  • Defer заменяет finally или try-with-resources
  • Panic / recover — встроенная обработка критических ошибок

Эти механизмы делают код Go компактным, безопасным и предсказуемым, при этом сохраняя контроль над состоянием и ресурсами без громоздкой структуры классов Java.


🌐 in English
Всего лайков:0

Оставить комментарий

Мой канал в социальных сетях
Отправляя email, вы принимаете условия политики конфиденциальности

Полезные статьи:

Atomic vs Mutex, Blocking vs Non‑Blocking, Read/Write Splitting (RWMutex), Logging | Concurrency Patterns и Best Practices  часть 5 | Go ↔ Java
В этой статье мы разберём ключевые подходы к работе с параллелизмом и синхронизацией в Go и Java. Мы сравним, как одни и те же задачи решаются на этих языках, покажем идиомы, паттерны и лучшие практик...
Context, propagation и cancellation patterns в Go vs Java | Паттерны, идиомы и лучшие практики Go
← Связанные статьи: Часть 1 — Error handling и defer в Go (Параллельность и синхронизация) | Паттерны, идиомы и лучшие практики Go 1. Context и его роль В Go context.Context используется для пере...
Современный подход к параллелизму в Java - Fork/Join Framework, CompletableFuture и виртуальные потоки (Project Loom)
Предисловие Мир программного обеспечения уже давно перестал быть спокойным океаном: сегодня это бурная экосистема, где каждая миллисекунда отклика приложения может стоить компании клиентов, репутации ...

Новые статьи:

Конкурентность — это не про «запустить много потоков». Это про договорённости между ними. Представь кухню ресторана: — повара (потоки / горутины) — заказы (задачи) — и главный вопрос: как они коорди...
История начинается не с академической теории, а с типичной production-проблемы. Представьте сервис: 48 CPU 300+ потоков нагрузка 200k операций в секунду много shared state Команда использует обы...
Когда HashMap начинает убивать продакшн: инженерная история ConcurrentHashMap
Представьте обычный продакшн-сервис. 32 CPU сотни потоков кэш конфигурации / сессий / rate limits десятки тысяч операций в секунду И где-то внутри — обычный Map. Сначала всё выглядит безобидно. Map&...
Fullscreen image