Java to Go

7 things to keep in mind when switching from Java to Go

Photo by Patrick Ward on Unsplash

1. Setup is simple; the language is even simpler

Installation steps here.

For the famous Hello World, in an empty directory, create a hello.go file and write the following code:

package mainimport "fmt"func main() {
fmt.Println("Hello, World!")

You run it by simply running go run hello.go in the terminal.

As you may have noticed, you don’t need semi-colons, naming is simple and suggestive, lower case are used for private (package) access and upper case is used for public access.

2. Creating projects is simple

A simple example would look like this:

project/                 # project folder
\_ cmd/ # keep the 'main' files here (optional)
|_ examples/ # show how functions/features are used
|_ internal/ # keep private modules here (internal libs)
|_ .gitignore # tells Git what not to stage for commits
|_ .makefile # used to simplify and run Go commands
|_ go.mod # specify your dependencies here
\_ # every project needs a readme, right

The idea is that there is no rule of how to set up your project. If it’s simple enough, you don’t even need these folders. Imagine you have a simple library where the code fits in one file (it’s possible with Go, lol). Then you’ll just have 1–2 go files: library.go and library_test.go.

3. You have Interfaces

package mainimport "fmt"type beverage interface {
name() string
caffeine() int
type coffee struct {
shots int
type tea struct {}func (c coffee) caffeine() int {
return c.shots * 75
func (c coffee) name() string {
return "coffee"
func (t tea) caffeine() int {
return 45
func (t tea) name() string {
return "tea"
func howMuchCaffeine(b beverage) {
fmt.Printf("%s has %d g of caffeine\n",, b.caffeine())
func main() {
c := coffee{shots: 2}
t := tea{}

4. But you also have Pointers

In Golang, you can pass arguments both by reference (pointers), and by value. The latter is usually cheaper, more convenient and simpler to understand by new Golang programmers. However, the former can be more efficient for very large structs.

Pass by value

type Person struct {
name string
func changeName(p Person) { = "Bob"
func main() {
person := Person {"Alice"}
fmt.Println(person) // prints "Alice"

Pass by reference

type Person struct {
name string
func changeName(p *Person) { = "Bob"
func main() {
person := Person {"Alice"}
fmt.Println(person) // prints "Bob"

5. Write once, run anywhere. Wait, what?

To build your code for a certian operating system, you simply need to set the $GOOS and $GOARCH environmental variables in your makefile for the build commands.

For OS-specific implementation, you simply need to add suffixes to the name of the files, e.g: example_darwin.go, example_windows.go, example_linux.go.

6. You don’t have Generics and you won’t miss them

7. Publishing your code is simple

This is supported by the Golang SDK and you don’t need to download or setup any additional tool.

Read about using go modules to get started.

Some resources I found useful in my journey:

💻 software engineer ⛰ outdoors enthusiast 👉

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store