Getting Started with Go (Golang) for Java Developers
If you're a Java developer curious about Go (also called Golang), you're in for an exciting and refreshing experience. While Go is simpler in syntax and tooling, itβs incredibly powerful and engineered for concurrency, performance, and developer productivity. This guide will help you transition smoothly from Java to Go.
Philosophy and Design Intent
Go was designed at Google with simplicity, speed, and ease of deployment in mind. It eliminates unnecessary complexity common in many languages (including Java) by:
Avoiding inheritance and generics (until Go 1.18+)
Having a lightweight type system
Using composition over inheritance
Compiling to a single binary with zero dependencies
Go Project Structure
No more src/main/java, pom.xml, or build.gradle. A Go project embraces simplicity and flat structure.
ποΈ Minimal Structure:
myapp/
βββ go.mod # Module definition (like a minimal `pom.xml`)
βββ main.go # Entry point with `main()`
βββ utils.go # Reusable helper functions or logic
π§ Initialising a Project
go mod init myapp
This creates a go.mod file that defines the module name and tracks dependencies.
π Typical Folder Layout for Larger Projects
myapp/
βββ go.mod
βββ go.sum
βββ cmd/ # Main application entry points
β βββ myapp/
β βββ main.go
βββ internal/ # Private packages not to be imported by others
β βββ config/
βββ pkg/ # Exported packages that can be imported by other projects
β βββ logger/
βββ api/ # HTTP handlers or gRPC APIs
βββ models/ # Data models or structs
βββ utils/ # Helper utilities
βββ test/ # Additional test data or integration tests
cmd/β entry points likemain()(can support multiple binaries)internal/β accessible only within your module (like Javaβsprivate)pkg/β reusable logic (like Java libraries)api/β handles incoming requests, typically withnet/httporginmodels/β represents your domain structs
π¦ Packages = Directories
Each directory is a package. Files in that directory should start with:
package packagename
To use them:
import "myapp/utils"
π§ͺ Run and Build
go run main.go # Compile and run
go build -o app # Build binary
This structure encourages modular, testable, and production-ready Go applications with minimal boilerplate.
Object-Oriented Concepts
Go doesnβt have classes in the traditional Java sense. Instead, it offers object-oriented features through structs, interfaces, and methods, without requiring everything to be wrapped inside a class.
Why Java Uses Classes
Java is a class-based object-oriented language, and every function, including main, must reside inside a class. This is rooted in Javaβs design:
Encapsulation: Grouping data and behavior into classes.
Inheritance: Sharing and extending behavior using class hierarchies.
Polymorphism: Achieved via subclassing and interfaces.
Everything is an object (except primitives), so classes are the foundation.
Go, however, moves away from this requirement by focusing on simplicity and practical design:
No classes β Uses structs and interfaces.
No inheritance β Encourages composition.
No constructors β Uses simple factory functions.
No access modifiers β Capitalized names are exported (public), lowercase are not.
Structs
Go uses structs to define complex data types (similar to Java POJOs):
type User struct {
Name string
Age int
}
Methods
Methods are functions associated with a type (like attaching a method to a struct):
func (u User) Greet() string {
return "Hello, " + u.Name
}
You can attach methods to any user-defined type, not just structs β a major difference from Java.
Interfaces
Go interfaces are implicit. If a type implements the methods required by an interface, it satisfies the interface β no implements keyword needed.
type Greeter interface {
Greet() string
}
func greetAll(g Greeter) {
fmt.Println(g.Greet())
}
This leads to more flexible and decoupled designs, as interfaces are satisfied automatically.
Syntax Differences
Program Structure
| Java | Go |
| Classes and methods inside class | Packages and functions |
public static void main() | func main() |
Java:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, Java!");
}
}
Go:
package main
import "fmt"
func main() {
fmt.Println("Hello, Go!")
}
Go eliminates class declarations and lets you write logic directly in functions.
Variable Declarations
| Java | Go |
| Typed and untyped variables | Supports both; also allows shorthand |
Java:
int age = 30;
String name = "Alice";
Go:
var age int = 30 // explicit type
name := "Alice" // inferred type (shorthand)
Functions
| Java | Go |
| Methods inside classes | Top-level func declarations |
Java:
int add(int a, int b) {
return a + b;
}
Go:
func add(a int, b int) int {
return a + b
}
In Go, function signatures include types for all parameters and the return value.
Control Structures
Most Java control structures are present in Go, but Go has some key differences:
No parentheses around conditions.
Curly braces are mandatory.
whileis replaced byfor.
Java:
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
Go:
for i := 0; i < 5; i++ {
fmt.Println(i)
}
Infinite loop in Go:
for {
// loop forever
}
Packages and Imports
In Java:
import java.util.*;
In Go:
import (
"fmt"
"math"
)
Each .go file belongs to a package. main is the entry point.
No Exceptions β Use Error Returns
Go avoids try-catch for error handling.
Java:
try {
int result = divide(4, 0);
} catch (ArithmeticException e) {
System.out.println("Error: " + e.getMessage());
}
Go:
result, err := divide(4, 0)
if err != nil {
fmt.Println("Error:", err)
}
Go forces you to deal with errors explicitly.
No Classes, Use Structs
Java:
class User {
String name;
int age;
}
Go:
type User struct {
Name string
Age int
}
Methods on Structs
In Go, you define methods on structs, not on classes.
func (u User) Greet() string {
return "Hello, " + u.Name
}
This achieves behavior similar to Javaβs class methods.
No null, Use nil
Go uses nil for:
Pointers
Maps
Slices
Channels
Interfaces
No NullPointerException, but you must still handle nil references manually.
No Constructors, Use Factory Functions
Go does not have constructors like Java. You use simple functions to create structs.
func NewUser(name string, age int) User {
return User{Name: name, Age: age}
}
Concurrency Made Easy
Go's concurrency model is based on goroutines and channels.
Goroutines
go fmt.Println("Running asynchronously")
Channels
ch := make(chan string)
// Send
go func() { ch <- "done" }()
// Receive
msg := <-ch
fmt.Println(msg)
This model is easier and safer than Java's Thread, Runnable, and ExecutorService.
Testing
Go has testing built in:
Test file:
// file: math_test.go
import "testing"
func TestAdd(t *testing.T) {
if Add(2, 3) != 5 {
t.Error("Add failed")
}
}
Run tests:
go test ./...
Tooling: Minimal and Fast
go fmtβ Formats codego vetβ Detects bugsgo runβ Compiles and runsgo buildβ Compiles to binarygo modβ Manages dependencies
You donβt need Maven or Gradle. The Go toolchain is self-sufficient.
Deployment Simplicity
Go compiles to a single native binary:
go build -o myapp
Just upload the binary to your server β no JVM, no containers (unless you want them).


