Pointers, functions, and execution control in Go vs Java | Types - Language
Series: Go for Java Developers — analyzing pointer, closures, defer, panic/recover
In this article, we will analyze how Go manages the state and lifecycle of functions. A feature of Go is the ease of working with pointers without complex arithmetic, powerful closures, and built-in mechanisms for safe termination and error handling. For a Java developer, this allows understanding the differences with familiar references, exceptions, and lambdas.
Pointers and value vs reference semantics
Pointers in Go allow working with variable addresses, but without pointer arithmetic. This is safer than in C, and analogous to references in Java, but with explicit syntax.
Example of a function with a pointer
// Go
func update(x *int) {
*x = 10
}
func main() {
a := 5
update(&a)
fmt.Println(a) // 10
}
Java equivalent:
// 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 makes references explicit through pointers. Value receiver works with a copy, pointer receiver works with the original.
Function literal / Closure — functions as objects
In Go, functions are full-fledged first-class objects. Closures allow maintaining state between calls.
Example of 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 equivalent (via lambda with object)
// 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 allows Go to keep the internal state of a function without creating a separate class. This is convenient for counters, generators, callbacks.
Defer — deferred execution (analogous to try-with-resources)
Defer executes a function at the end of the current block. This is convenient for closing resources or freeing memory.
Example of defer
// Go
func main() {
defer fmt.Println("world")
fmt.Println("hello")
}
// Output:
// hello
// world
Java equivalent (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 is convenient for clean code, especially with files, sockets, and other resources.
Panic / Recover — handling critical errors
In Go, panic is analogous to unchecked exceptions in Java, but more controllable. Recover allows intercepting the panic and continuing execution.
Example 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 equivalent
// 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 and recover allow for graceful handling of critical errors without breaking the entire flow of execution.
Comparison of key concepts Go ↔ Java
| Concept | Go | Java | Comment |
|---|---|---|---|
| Pointers | explicit pointer, no arithmetic | object references | Go makes the reference explicit |
| Value vs reference semantics | value receiver / pointer receiver | primitive vs object reference | Pointer receiver modifies the original |
| Closure | function literal, captures vars | lambda / anonymous class | Can store function state |
| Defer | deferred execution | try-with-resources / finally | Convenient for releasing resources |
| Panic / Recover | runtime error / catch | unchecked exception / try-catch | Catching critical errors |
Practical Output
For a Java developer learning Go, it is important to understand:
- Pointers in Go are safe and explicit, without arithmetic
- Value vs pointer receiver allows controlling data changes
- Functions are first-class objects, closures maintain state
- Defer replaces finally or try-with-resources
- Panic / recover – built-in handling of critical errors
These mechanisms make Go code compact, safe, and predictable, while maintaining control over state and resources without the bulky class structure of Java.
Оставить комментарий
Useful Articles:
New Articles: