A field guide · Go 1.27 · Java 25
Java to Go: a guide for Java developers
Go, taught from the Java you already know. Every concept pairs idiomatic Java with idiomatic Go, then explains why Go chose differently, so you build the mental model instead of translating syntax.
How every section reads
The same job in Java and in Go, with the reasoning underneath. Here is error handling, the shift most Java developers feel first:
try {
User user = repo.findById(id);
return render(user);
} catch (UserNotFoundException e) {
return notFound();
}
// Other exceptions keep unwinding,
// invisible at this call site.user, err := repo.FindByID(ctx, id)
if errors.Is(err, ErrNotFound) {
return notFound()
}
if err != nil {
return fmt.Errorf("user %s: %w", id, err)
}
return render(user)Contents
31 sections in 7 parts
Orientation
The mindset shift, how code is organised, and how dependencies work.
- 00Go Mental ModelGo is not Java with different syntax. The ten differences that shape everything else, and how to read the rest of this guide.
- 01Packages & ImportsA package is a directory, capitalisation is the only access modifier, and there are exactly two visibility scopes.
- 02Dependency ManagementModules, go.mod and go.sum in place of Maven or Gradle: adding dependencies, major versions, local development and private repositories.
Types & Data
Zero values, structs, interfaces, pointers and the built-in collections.
- 03Types & VariablesZero values instead of null, explicit integer sizes, no implicit conversions, and enums built from named types and iota.
- 04Strings & FormattingStrings are immutable UTF-8 bytes, not UTF-16 chars. Indexing, runes, building strings efficiently, fmt verbs and strconv.
- 05StructsStructs hold data, methods are declared beside them, constructors are plain functions, and embedding replaces inheritance.
- 06InterfacesInterfaces are satisfied implicitly, defined by the consumer, and kept small. Accept interfaces, return structs.
- 07PointersJava hides references; Go makes you choose between a value and a pointer. When to use each, and why it is safer than C.
- 08any / interface{}The empty interface is Go’s Object: type assertions, type switches, and the nil-interface trap that catches every Java developer once.
- 09Slices & MapsSlices and maps are built-in types, not library classes. How slices share memory, why append must be reassigned, and the slices and maps packages.
Functions & Errors
Multiple returns, cleanup with defer, and errors as ordinary values.
- 10FunctionsMultiple return values, first-class functions and closures, and what replaces overloading, default arguments and builders.
- 11Defer
deferreplaces try/finally and try-with-resources: cleanup next to acquisition, LIFO order, and panic/recover for the truly exceptional. - 12Error HandlingErrors are values: sentinel errors, custom types, wrapping with %w, errors.Is and errors.As, joining, and when a panic is acceptable.
- 13Blank IdentifierThe underscore discards values on purpose: ignored results, side-effect imports, and compile-time interface checks.
Concurrency
Goroutines, channels, locks, cancellation and the patterns that combine them.
- 14GoroutinesGoroutines vs platform and virtual threads, the go keyword, the loop-variable change in Go 1.22, WaitGroup, and how to see what is running.
- 15ChannelsTyped pipes between goroutines: unbuffered handoffs, buffered queues, closing, select, timeouts and the rules for nil and closed channels.
- 16Sync PrimitivesMutex, RWMutex, Once, atomics and sync.Map: guarding shared state when a channel is the wrong tool, and why Go locks are not reentrant.
- 17Goroutine ManagementProduction patterns: stopping goroutines, errgroup for fail-fast fan-out, bounded concurrency, worker pools, fan-in, and finding leaks.
- 18Context
context.Contextcarries cancellation, deadlines and request-scoped values through every call. It replaces interruption, timeouts and ThreadLocal. - 19Defer — Advanceddefer in concurrent code: unlocking, closing channels, containing panics in background goroutines, and annotating errors on the way out.
Generics & Iterators
Type parameters, constraints, and range-over-func iterators.
- 20GenericsType parameters on functions, types and (since Go 1.27) methods; constraints with interfaces, unions and ~; and what Go generics deliberately leave out.
- 21IteratorsRange-over-func iterators (Go 1.23+) in place of Iterable and Stream: writing them with yield, consuming them with for-range, and lazy pipelines.
Building Services
From main() to a tested, observable HTTP service you can ship.
- 22Init & Main LifecycleHow a Go program starts, why init() should be rare, wiring dependencies by hand instead of Spring, and a production main() with graceful shutdown.
- 23Project Layout & EcosystemHow Go services are laid out on disk, which Java library maps to which Go tool, and when code generation (sqlc, easyjson) is worth it.
- 24JSON & HTTP APIsencoding/json in place of Jackson, net/http routing in place of Spring MVC, request limits and error mapping, middleware, and calling other services safely.
- 25HTTP Concurrency ModelThread-per-request, reactive WebFlux, virtual threads and Go’s goroutine-per-request: how each model handles slow I/O, and what that means for your code.
- 26TestingThe built-in test runner: table-driven tests, fakes instead of Mockito, httptest, the race detector, fuzzing, testing time with synctest, and benchmarks.
- 27Logging & Observabilitylog/slog in place of SLF4J and Logback, request context in every log line without MDC, redacting secrets, and metrics, tracing and profiling.
- 28Tooling & DeploymentOne go command instead of a build tool, formatting and linting, static binaries and small containers, embedded assets, and tuning the GC instead of -Xmx.
Wrap-up
The traps Java developers hit most, and the whole mapping on one page.